In: Computer Science
This violates Liskov Substitution Principle (LSP), can someone explain why and refactor it so it does not?
public abstract class Bird { public abstract void LayEgg(); public abstract void FlyAway(); } public class Penguin : Bird { public override void LayEgg() { //Make husband penguin do all the incubation work. } public override void FlyAway() { //Penguins can't fly. throw new NotImplementedException(); } public void SwimAway() { //Swimming is way more fun. } }
Liskov substitution principle defines that objects of a superclass(Base class) shall be replaceable with objects of its subclasses(derived class) without breaking the application. This requires the objects of your subclasses to behave in the same way as the objects of your superclass.
So thats the basic idea of Liskov substitution principle. In the sample code that you gave we have a super class Bird and a sub class Penguin.
So class definition here is Penguin is a Bird, which can also be written as all Penguins are Birds but not all Birds are Penguins. So A Penguin must have all the basic(abstract) definitions of a Bird. we have two abstract methods in Bird LayEgg() and FlyAway(). Penguin implements LayEgg() but not FlyAway(), since penguins cannot fly. This violates the Liskov Substitution principle.
This can be refactored by further introducing two subclasses under Bird namely FlyingBird and FlightlessBird. And inheriting Penguin from the class FlightlessBird.
By doing this we simplify the definition of bird to "All Birds Lays Eggs" which is much simpler than All Birds lay Eggs and Fly". We delegate the other definition to next level of subclasses which introduce their own definitions, without changing the original definition of the Bird.
Refactored code:
public abstract class Bird {
public abstract void LayEgg();
}
public abstract class FlyingBird : Bird {
public abstract void FlyAway();
}
public abstract class FlightlessBird : Bird
{
}
public class Penguin:FlightlessBird
{
public override void LayEgg()
{
//Make husband penguin do all the incubation work.
}
public void SwimAway()
{
//Swimming is way more fun.
}
}
Inheritance diagram: