Asdfasf

Saturday, February 16, 2013

Liskov Substitution Principle (LSP)

This principle is L of S.O.L.I.D design principles.

According to Liskov Substitution Principle, Subtypes must be substitutable for super type i.e. methods or functions which uses super class type must be able to work with object of sub class without any issue”. LSP is closely related to Single responsibility principle and Interface Segregation Principle. If a class has more functionality than subclass might not support some of the functionality and does violated LSP. In order to follow LSP design principle, derived class or sub class must enhance functionality not reducing it. (See Reference)

How can we identify LSP violation?

 Derived class may require less functionalities than the Base class, so some methods would be redundant. We might be using IS-A to check for Super-Sub relationships, but LSP doesn’t use only IS-A, but it also requires that the Sub types must be substitutable for the Super class. And one cannot decide the substitutability of sub class in isolation. One has to consider how the clients of the class hierarchy are going to use it. (See Reference)

Lets take look at the code below which violates LSP by binding swim and fly functionality to Base class Bird and use this functionalities by sub classes.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.util.ArrayList;  
 import java.util.List;  
 /*  
  * This class demonstrates Liskov Substitution Principle  
  */  
 public class LSPViolation {  
      abstract class Bird{  
           public abstract String getName();  
           public void sound(){  
                System.out.println(getName() + " sounds");  
           }  
           public void fly(){  
                System.out.println(getName() + " flies");  
           }  
           public void swim(){  
                System.out.println(getName() + " swims");  
           }  
      }  
      class Canary extends Bird{  
           public void swim(){  
                throw new UnsupportedOperationException( 
                                          "Canary can not swim");  
           }  
           public String getName() {  
                return "canary";  
           }  
      }  
      class Penguin extends Bird{  
           public String getName() {  
                return "penguin";  
           }  
           public void fly(){  
                throw new UnsupportedOperationException( 
                                          "penguin can not fly");  
           }  
      }  
      public static void main(String[] args) {  
           LSPViolation lspViolation = new LSPViolation();  
           List<Bird> birds = new ArrayList<Bird>();  
           birds.add(lspViolation.new Penguin());  
           birds.add(lspViolation.new Canary());  
           for (Bird bird : birds){  
                bird.sound();  
                bird.swim();  
                bird.fly();  
           }  
      }  
 }  

When we run above code, boom!

 penguin sounds  
 penguin swims  
 Exception in thread "main" java.lang.UnsupportedOperationException: penguin can not fly  
   at LSPViolation$Penguin.fly(LSPViolation.java:40)  
   at LSPViolation.main(LSPViolation.java:54)  

So lets fix it by seperating responsibilities as SwimmableBird and FlyableBird:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 /*  
  * This class demonstrates Liskov Substitution Principle  
  */  
 public class LSPCompatible {  
      abstract class Bird{  
           public abstract String getName();  
           public void sound(){  
                System.out.println(getName() + " sounds");  
           }  
      }  
      abstract class FlyableBird extends Bird{  
           public void fly(){  
                System.out.println(getName() + " flies");  
           }  
      }  
      abstract class SwimmableBird extends Bird{  
           public void swim(){  
                System.out.println(getName() + " swims");  
           }  
      }  
      class Canary extends FlyableBird{  
           public String getName() {  
                return "canary";  
           }  
      }  
      class Penguin extends Bird{  
           public String getName() {  
                return "penguin";  
           }  
      }  
 }  
.

No comments: