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}}
publicclassRacingCarextendsCar{@OverridepublicdoublegetCabinWidth(){//UNIMPLEMENTED}publicdoublegetCockpitWidth(){//return the cockpit width of the racing car}}
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());}}
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}}
publicclassCarextendsVehicle{@OverridepublicdoublegetInteriorWidth(){returnthis.getCabinWidth();}publicdoublegetCabinWidth(){//return cabin width}}
publicclassRacingCarextendsVehicle{@OverridepublicdoublegetInteriorWidth(){returnthis.getCockpitWidth();}publicdoublegetCockpitWidth(){//return the cockpit width of the racing car}}
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());}}
**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;}}
publicclassInHouseProductextendsProduct{publicvoidapplyDiscount(){discount=discount*1.5;// 1.5 times more discount on InHouseProducts}}
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());}}
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;}}
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());}}
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)
For further actions, you may consider blocking this person and/orreporting abuse