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
public class Car{ public double getCabinWidth(){ //return cabin width } }
public class RacingCar extends Car{ @Override public double getCabinWidth(){ //UNIMPLEMENTED } public double getCockpitWidth(){ //return the cockpit width of the racing car } }
RacingCar overrides the getCabinWidth() of the car class but leaves it unimplemented 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
public class CarUtil{ Car car1 = new Car(); Car car2 = new Car(); Car car3 = new RacingCar(); List<car> myCars = new ArrayList(); myCars.add(car1); myCars.add(car2); myCars.add(car3); // this will not work in 3rd iteration, because the getCabinWidth() in RacingCar is not implemented for(Car car : myCars){ System.out.println(car.getCabinWidth()); } } </car>
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 both Car and RacingCar
We will create a very generic parent class called Vehicle
public class Vehicle{ public double getInteriorWidth(){ //return the interior width } }
public class Car extends Vehicle{ @Override public double getInteriorWidth(){ return this.getCabinWidth(); } public double getCabinWidth(){ //return cabin width } }
public class RacingCar extends Vehicle{ @Override public double getInteriorWidth(){ return this.getCockpitWidth(); } public double getCockpitWidth(){ //return the cockpit width of the racing car } }
public class VehicleUtils{ Vehicle vehicle1 = new Car(); Vehicle vehicle2 = new Car(); Vehicle vehicle2 = new RacingCar(); List<vehicle> vehicles = new ArrayList(); vehicles.add(vehicle1); vehicles.add(vehicle2); vehicles.add(vehicle3); for(Vehicle vehicle : vehicles){ System.out.println(vehicle.getInteriorWidth()); } } </vehicle>
**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)
public class Product{ public double discount = 20;//x amount of discount on all the third-party products on Amazon public double getDiscount(){ return discount; } }
public class InHouseProduct extends Product{ public void applyDiscount(){ discount = discount*1.5;// 1.5 times more discount on InHouseProducts } }
public class PricingUtils{ Product p1 = new Product(); Product p2 = new Product(); Product p2 = new InHouseProduct(); List<product> products = new ArrayList(); products.add(p1); products.add(p2); products.add(p2); for(Product product : products){ if(product instanceOf InHouseProduct){ ((InHouseProduct)product).applyDiscount(); } System.out.println(product.getDiscount()); } } </product>
Note that the if statement is involved in updating the discount amount of InHouseProduct which is against the Liskov substitution principle ( as we should have been able to replace the object Product with its subtype InHouseProduct), but here in if statement we are manually updating the discount amount which should not be done.
A slight modification in the InHouseProduct class will fix this issue
public class InHouseProduct extends Product{ @Override public double getDiscount(){ applyDiscount(); return discount; } public void applyDiscount(){ discount = discount*1.5; } }
And finally removing the if statement from the PricingUtils class
public class PricingUtils{ Product p1 = new Product(); Product p2 = new Product(); Product p2 = new InHouseProduct(); List<product> products = new ArrayList(); products.add(p1); products.add(p2); products.add(p2); for(Product product : products){ System.out.println(product.getDiscount()); } } </product>
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)
The above is the detailed content of Liskov Substitution Principle. For more information, please follow other related articles on the PHP Chinese website!

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa

This article explores integrating functional programming into Java using lambda expressions, Streams API, method references, and Optional. It highlights benefits like improved code readability and maintainability through conciseness and immutability

The article discusses using JPA for object-relational mapping with advanced features like caching and lazy loading. It covers setup, entity mapping, and best practices for optimizing performance while highlighting potential pitfalls.[159 characters]

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.

This article explains Java's NIO API for non-blocking I/O, using Selectors and Channels to handle multiple connections efficiently with a single thread. It details the process, benefits (scalability, performance), and potential pitfalls (complexity,

The article discusses creating and using custom Java libraries (JAR files) with proper versioning and dependency management, using tools like Maven and Gradle.

This article details Java's socket API for network communication, covering client-server setup, data handling, and crucial considerations like resource management, error handling, and security. It also explores performance optimization techniques, i


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Safe Exam Browser
Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.