190 likes | 514 Views
OO Design: Liskov Substitution Principle. Liskov Substitution Principle. But we must be careful when we implement subclass to e nsure that we don’t violate the LSP. public class Rectangle { private double width, height; Rectangle(double w, double h) { width = w; height = h; }
E N D
OO Design:Liskov Substitution Principle OO Design: Liskov Substitution Principle
Liskov Substitution Principle • But we must be careful when we implement subclass to ensure that we don’t violate the LSP public class Rectangle { private double width, height; Rectangle(double w, double h) { width = w; height = h; } public double area() { return width * height; } public void setWidth(double w) { width = w;} public void setHeight(double h){ height = h;} public double getWidth() { return width; } public double getHeight() { return height;} } OO Design: Liskov Substitution Principle
LSP Example public class Square extends Rectangle { Square(double s) { super(s,s); } public void setWidth(double w) { super.setWidth(w); super.setHeight(w);} public void setHeight(double h){ super.setWidth(h); super.setHeight(h);} } OO Design: Liskov Substitution Principle
LSP Example public class TestRectangle { public static void testLSP(Rectangle r) { r.setWidth(4.0); r.setHeight(5.0); System.out.println(r.area()); assert(r.area()= 20); } } OO Design: Liskov Substitution Principle
What Went Wrong? • Consider the postcondition for setWidth in classes Rectangle and Square: • Rectangle: width == w && height == old.height • Square: width == w && height == w • The postcondition for Square is weaker than the postcondition for Rectangle because it does not attempt to enforce the clause (height == old.height) OO Design: Liskov Substitution Principle
Rule • When you override a method in a base class, the precondition of the overriding method should be weaker than the precondition of the overriden method: • The more useful a procedure is for clients • The more difficult it is to implement correctly “Weaker” means the derived class should consider more inputs to the overriding method OO Design: Liskov Substitution Principle
Rule • When you override a method in a base class, the postcondition of the overriding method should be stronger than the postcondition of the overriden method: “Stronger” means the derived class should produce less outputs from the overriding method OO Design: Liskov Substitution Principle
So, void testRectangleSetWidth(Rectangle rec) { doubleoldHeight = rec.getHeight(); rec.setWidth(5); // postconditions of Rectangle assertTrue (5 == rec.getWidth() && oldHeight == rec.getHeight()); } OO Design: Liskov Substitution Principle
Subtype Substitution • If B is a subtype of A, everywhere the code expects an A, a B can be used instead • Examples: c1 must be a subtype of Cell (note A is a subtype of A) Cell c = c1; Cell c = new ConwayLifeCell (); ConwayLifeCell c = new Cell (); OO Design: Liskov Substitution Principle
Inheritance • To implement a subtype, it is often useful to use the implementation of its supertype • This is also called “subclassing” class B extends A B is a subtype of A B inherits from A class C implements F C is a subtype of F both subtyping and inheritance just subtyping No way to get inheritance without subtyping in Java OO Design: Liskov Substitution Principle
How do we know if saying B is a subtype of Ais safe? Substitution Principle: If B is a subtype of A, everywhere the code expects an A, a B can be used instead and the program still satisfies its specification OO Design: Liskov Substitution Principle
Subtype Condition 1: Signature Rule We can use a subtype method where a supertype methods is expected: • Subtype must implement all of the supertype methods • Argument types must not be more restrictive • Result type must be at least as restrictive • Subtype method must not throw exceptions that are not subtypes of exceptions thrown by supertype OO Design: Liskov Substitution Principle
Signature Rule class A { public RA m (PA p) ; } class B extends A { public RB m (PB p) ; } RB must be a subtype of RA: RB <= RA PB must be a supertype of PA: PB >= PA OO Design: Liskov Substitution Principle
Substitution Mystery … (in client code) MysteryType1 mt1; MysteryType2 mt2; MysteryType3 mt3; … (anything could be here) mt1 = mt2.m (mt3); • If the Java compiler accepts this code, which of these are guaranteed • to be true: • The static type of mt2 is MysteryType2 • At the last statement, the run-time type of mt2 is MysteryType2 • MysteryType2 has a method named m • The MysteryType2.m method takes a parameter of type MysteryType3 • The MysteryType2.m method returns a subtype of MysteryType1 • After the last statement, the run-time type of mt1 is MysteryType1 OO Design: Liskov Substitution Principle
… (in client code) MysteryType1 mt1; MysteryType2 mt2; MysteryType3 mt3; … (anything could be here) mt1 = mt2.m (mt3); • The static type of mt2 is MysteryType2 • At the last statement, the run-time type of mt2 is MysteryType2 • MysteryType2 has a method named m • The MysteryType2.m method takes a parameter of type MysteryType3 • The MysteryType2.m method returns a subtype of MysteryType1 • After the last statement, the run-time type of mt1 is MysteryType1 TRUE: the static type is obvious from the declaration. FALSE: we only know the run-time type <= MysteryType2 TRUE FALSE: we only know it takes a parameter >= MysteryType3 TRUE: the assignment type checking depends on this FALSE: we only know that the run-time type <= MysteryType1 OO Design: Liskov Substitution Principle