Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Prashant Mishra
Prashant Mishra

Posted on

     

Liskov Substitution Principle

Objects should be replaceable with their subtype without affecting the correctness of the code

Let's understand this with inheritance(Is-a relationship)
example: Ostrich is a bird, Hunchback is a car, etc.

Example: Racing-car is a car

publicclassCar{publicdoublegetCabinWidth(){//return cabin width}}
Enter fullscreen modeExit fullscreen mode
publicclassRacingCarextendsCar{@OverridepublicdoublegetCabinWidth(){//UNIMPLEMENTED}publicdoublegetCockpitWidth(){//return the cockpit width of the racing car}}
Enter fullscreen modeExit fullscreen mode

RacingCar overrides thegetCabinWidth() of the car class but leaves itunimplemented because Racing cars don't have cabin width( if you see a Formula 1 racing car, it does not have any interior space, all it has is just a cockpit where the driver sits)
Hence the interior space in a racing car is called a cockpit.
Note: Racing cars have some specifications that might not match the generic car

publicclassCarUtil{Carcar1=newCar();Carcar2=newCar();Carcar3=newRacingCar();List<Car>myCars=newArrayList<>();myCars.add(car1);myCars.add(car2);myCars.add(car3);// this will not work in 3rd iteration, because the getCabinWidth() in RacingCar is not implementedfor(Carcar:myCars){System.out.println(car.getCabinWidth());}}
Enter fullscreen modeExit fullscreen mode

This is a design that has been exposed, as the for loop will fail for the third iteration.
To fix this we have to strike at the root which is Inheritance itself.


Solution 1 : (Breaking the Hierarchy)

We have to break the inheritance, instead, we will come up with a common parent for bothCar andRacingCar

We will create a very generic parent class calledVehicle

publicclassVehicle{publicdoublegetInteriorWidth(){//return the interior width}}
Enter fullscreen modeExit fullscreen mode
publicclassCarextendsVehicle{@OverridepublicdoublegetInteriorWidth(){returnthis.getCabinWidth();}publicdoublegetCabinWidth(){//return cabin width}}
Enter fullscreen modeExit fullscreen mode
publicclassRacingCarextendsVehicle{@OverridepublicdoublegetInteriorWidth(){returnthis.getCockpitWidth();}publicdoublegetCockpitWidth(){//return the cockpit width of the racing car}}
Enter fullscreen modeExit fullscreen mode
publicclassVehicleUtils{Vehiclevehicle1=newCar();Vehiclevehicle2=newCar();Vehiclevehicle2=newRacingCar();List<Vehicle>vehicles=newArrayList<>();vehicles.add(vehicle1);vehicles.add(vehicle2);vehicles.add(vehicle3);for(Vehiclevehicle:vehicles){System.out.println(vehicle.getInteriorWidth());}}
Enter fullscreen modeExit fullscreen mode

**Breaking the hierarchy: Break the hierarchy if the substitution fails


Solution 2:Tell don't ask

Let's take another example of Amazon
Amazon offers x amount of discount on all the third-party products.
And offers 1.5 times x on all its in-house products (Amazon Basics products are Amazon in-house products)

publicclassProduct{publicdoublediscount=20;//x amount of discount on all the third-party products on AmazonpublicdoublegetDiscount(){returndiscount;}}
Enter fullscreen modeExit fullscreen mode
publicclassInHouseProductextendsProduct{publicvoidapplyDiscount(){discount=discount*1.5;// 1.5 times more discount on InHouseProducts}}
Enter fullscreen modeExit fullscreen mode
publicclassPricingUtils{Productp1=newProduct();Productp2=newProduct();Productp2=newInHouseProduct();List<Product>products=newArrayList<>();products.add(p1);products.add(p2);products.add(p2);for(Productproduct:products){if(productinstanceOfInHouseProduct){((InHouseProduct)product).applyDiscount();}System.out.println(product.getDiscount());}}
Enter fullscreen modeExit fullscreen mode

Note that theif statement is involved in updating the discount amount ofInHouseProduct which isagainst the Liskov substitution principle ( as we should have been able to replace the objectProduct with its subtypeInHouseProduct), but here in if statement we are manually updating the discount amount which should not be done.

A slight modification in theInHouseProduct class will fix this issue

publicclassInHouseProductextendsProduct{@OverridepublicdoublegetDiscount(){applyDiscount();returndiscount;}publicvoidapplyDiscount(){discount=discount*1.5;}}
Enter fullscreen modeExit fullscreen mode

And finally removing the if statement from thePricingUtils class

publicclassPricingUtils{Productp1=newProduct();Productp2=newProduct();Productp2=newInHouseProduct();List<Product>products=newArrayList<>();products.add(p1);products.add(p2);products.add(p2);for(Productproduct:products){System.out.println(product.getDiscount());}}
Enter fullscreen modeExit fullscreen mode

Tell don't ask: Here we are telling the utils class to print all the discounts and the utils class does not have to ask anything ( as it was asking by if statement earlier)


Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

There is always a price for those who persevere.
  • Location
    India
  • Education
    Computer Science
  • Work
    Software Engineer @JPMorganChase&Co.
  • Joined

More fromPrashant Mishra

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp