Liskov Substitution Principle

advertisement
OO Design:
Liskov Substitution Principle
4/13/2015
OO Design: Liskov Substitution
1
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;}
}
4/13/2015
OO Design: Liskov Substitution
2
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);}
}
4/13/2015
OO Design: Liskov Substitution
3
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);
}
}
4/13/2015
OO Design: Liskov Substitution
4
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)
4/13/2015
OO Design: Liskov Substitution
5
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
4/13/2015
OO Design: Liskov Substitution
6
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
4/13/2015
OO Design: Liskov Substitution
7
So,
void testRectangleSetWidth(Rectangle rec)
{
double oldHeight = rec.getHeight();
rec.setWidth(5);
// postconditions of Rectangle
assertTrue (5 == rec.getWidth() &&
oldHeight == rec.getHeight());
}
4/13/2015
OO Design: Liskov Substitution
8
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
Cell c = c1; (note A is a subtype of A)
Cell c = new ConwayLifeCell ();
ConwayLifeCell c = new Cell ();
4/13/2015
OO Design: Liskov Substitution
9
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
4/13/2015
OO Design: Liskov Substitution
10
How do we know if saying
B is a subtype of A
is 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
4/13/2015
OO Design: Liskov Substitution
11
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
4/13/2015
OO Design: Liskov Substitution
12
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
4/13/2015
OO Design: Liskov Substitution
13
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:
a. The static type of mt2 is MysteryType2
b. At the last statement, the run-time type of mt2 is MysteryType2
c. MysteryType2 has a method named m
d. The MysteryType2.m method takes a parameter of type MysteryType3
e. The MysteryType2.m method returns a subtype of MysteryType1
f. After the last statement, the run-time type of mt1 is MysteryType1
4/13/2015
OO Design: Liskov Substitution
14
…
(in client code)
MysteryType1 mt1;
MysteryType2 mt2;
MysteryType3 mt3;
…
(anything could be here)
mt1 = mt2.m (mt3);
a. The static type of mt2 is MysteryType2
TRUE: the static type is obvious from the declaration.
b. At the last statement, the run-time type of mt2 is MysteryType2
FALSE: we only know the run-time type <= MysteryType2
c. MysteryType2 has a method named m
TRUE
d. The MysteryType2.m method takes a parameter of type MysteryType3
FALSE: we only know it takes a parameter >= MysteryType3
e. The MysteryType2.m method returns a subtype of MysteryType1
TRUE: the assignment type checking depends on this
f. After the last statement, the run-time type of mt1 is MysteryType1
FALSE: we only know that the run-time type <= MysteryType1
4/13/2015
OO Design: Liskov Substitution
15
Download