What if every part you swapped just worked perfectly without surprises?
Why Liskov Substitution Principle in LLD? - Purpose & Use Cases
Imagine you have a family of remote controls for different devices. You try to use a remote control designed for a TV to operate a DVD player, but it doesn't work as expected because the buttons behave differently.
When you manually swap parts or components without ensuring they behave the same way, your system breaks. This causes confusion, errors, and extra work to fix unexpected behaviors.
The Liskov Substitution Principle ensures that any component or class can be replaced by its subtype without changing the correctness of the program. This means you can swap parts freely, and everything still works smoothly.
class TVRemote { void pressPlay() { /* plays TV channel */ } } class DVDRemote extends TVRemote { void pressPlay() { throw Exception('Not supported'); } }
interface Remote {
void pressPlay();
}
class TVRemote implements Remote {
void pressPlay() { /* plays TV channel */ }
}
class DVDRemote implements Remote {
void pressPlay() { /* plays DVD */ }
}It enables building flexible systems where components can be swapped or extended without breaking existing functionality.
Think of a universal charger that works with any phone brand without causing damage or malfunction.
Ensures subtypes can replace base types without errors.
Prevents unexpected behavior when swapping components.
Supports flexible and maintainable system design.
Practice
What does the Liskov Substitution Principle (LSP) primarily ensure in system design?
Solution
Step 1: Understand LSP definition
LSP states that objects of a child class should be replaceable with objects of the parent class without breaking the program.Step 2: Analyze options against LSP
Only Child classes can replace parent classes without affecting correctness correctly describes this principle. Other options contradict LSP or are unrelated.Final Answer:
Child classes can replace parent classes without affecting correctness -> Option AQuick Check:
Liskov Substitution Principle = Child replaces Parent [OK]
- Thinking LSP forbids inheritance
- Confusing LSP with interface segregation
- Believing child classes can change parent behavior arbitrarily
Which of the following class declarations follows the Liskov Substitution Principle?
class Bird {
fly() {}
}
class Penguin extends Bird {
fly() {
throw new Error('Cannot fly');
}
}Solution
Step 1: Analyze Penguin's fly method
Penguin throws an error on fly(), but Bird expects fly() to work normally.Step 2: Check LSP compliance
Since Penguin cannot be used where Bird is expected (fly method fails), it violates LSP.Final Answer:
No, because Penguin breaks expected behavior of Bird -> Option BQuick Check:
Child must not break parent behavior = No [OK]
- Ignoring method behavior changes in child
- Assuming inheritance alone guarantees LSP
- Thinking overriding with error is allowed
Consider the following code snippet. What will be the output?
class Vehicle {
start() { return 'Vehicle started'; }
}
class Car extends Vehicle {
start() { return 'Car started'; }
}
function startVehicle(v) {
return v.start();
}
const myCar = new Car();
console.log(startVehicle(myCar));Solution
Step 1: Understand method overriding
Car overrides start() method to return 'Car started'.Step 2: Trace function call
startVehicle(myCar) calls myCar.start(), which returns 'Car started'.Final Answer:
'Car started' -> Option CQuick Check:
Overridden method returns child's message [OK]
- Expecting parent method output instead of child's
- Confusing method names or forgetting override
- Assuming error due to polymorphism
Identify the violation of Liskov Substitution Principle in the code below and select the fix.
class Rectangle {
setWidth(w) { this.width = w; }
setHeight(h) { this.height = h; }
area() { return this.width * this.height; }
}
class Square extends Rectangle {
setWidth(w) {
this.width = w;
this.height = w;
}
setHeight(h) {
this.width = h;
this.height = h;
}
}Solution
Step 1: Identify LSP violation
Square changes behavior of setWidth and setHeight, breaking Rectangle's expectations.Step 2: Choose fix
To follow LSP, Square and Rectangle should not be in inheritance relation if behaviors differ fundamentally.Final Answer:
Use separate classes without inheritance for Square and Rectangle -> Option AQuick Check:
Different behavior means no inheritance [OK]
- Ignoring behavioral changes in overridden methods
- Trying to fix by only overriding area()
- Assuming inheritance always fits shapes
You are designing a payment system with a base class PaymentMethod and subclasses CreditCard and Bitcoin. The base class has a method processPayment(amount) that returns a success message. However, Bitcoin payments require additional confirmation steps and may fail differently. How should you design these classes to follow the Liskov Substitution Principle?
Solution
Step 1: Understand LSP in payment context
Subclasses must behave so they can replace base class without breaking client code.Step 2: Design consistent behavior
Bitcoin and CreditCard should implement processPayment so it returns success/failure in a consistent way, hiding internal differences.Final Answer:
Keep Bitcoin and CreditCard as subclasses but ensure processPayment behaves consistently and returns success/failure uniformly -> Option DQuick Check:
Consistent behavior across subclasses = LSP compliance [OK]
- Throwing errors breaking expected method contracts
- Ignoring different failure modes without abstraction
- Removing inheritance unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
