Consider the classic example in Java
// Violation of Likov's Substitution Principle
class Rectangle
{
protected int m_width;
protected int m_height;
public void setWidth(int width){
m_width = width;
}
public void setHeight(int height){
m_height = height;
}
public int getWidth(){
return m_width;
}
public int getHeight(){
return m_height;
}
public int getArea(){
return m_width * m_height;
}
}
class Square extends Rectangle
{
public void setWidth(int width){
m_width = width;
m_height = width;
}
public void setHeight(int height){
m_width = height;
m_height = height;
}
}
class LspTest
{
private static Rectangle getNewRectangle()
{
// it can be an object returned by some factory ...
return new Square();
}
public static void main (String args[])
{
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5);
r.setHeight(10);
// user knows that r it's a rectangle.
// It assumes that he's able to set the
// width and height as for the base class
System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
}
}
I think the whole point is that object of child class can be treated(type casting?) like parent class in static typed language like Java:
Rectange rectange = new Square();
but in Ruby I don't think that make any sense, same thing in Ruby:
class Rectangle
attr_accessor :width, :height
def getArea()
@width * @height
end
end
class Square < Rectangle
def width=(number)
super(number)
@height = number
end
def height=(number)
super(number)
@width = number
end
end
s = Square.new(100)
puts s.class
s.width = 50
puts s.height
become I can alway check the class of the object by using:
rectange.class
in this case, if the code in Ruby it will return Square
so I won't treat it like Rectange
.
Could anyone explain me the point for applying LSP in dynamic typed language like Ruby?
Although I still don't know what problem it may cause to let Square be a child of Rectangle. but now I learn to tell whether it violet the LSP or not by using the way:
for square
object is an instance of Square
Class, rectangle
object is an instance of Rectangle
class
the width=
is a method in both of them
width=
in square
can not be replaced by width=
in rectangle
because it won't set the height as the one defined in 'square' does.
Am I wrong with this way of thinking?
And Also I learned to use the violet the contact of 'width=' method in the Rectangle
Class to analysis this problem:
for width=
in 'Rectangle' class
precondition: @width
and @height
has some value.
postconditon: @width
change to the new value, @height
remain the untouched.
for 'width=' in Square
class
precondition: same as above
postconditon: '@width' change to the the new value, @height
change to the new value
according to the principle : require no more, promise no less
the @height
is changed, so promise is not fulfilled, thus it can't be inheritance
Does anyone can give me some advice about my way of analysis this problem by using DBC
?