Имеет ли смысл LSP для языка динамической типизации, такого как Ruby?
Рассмотрим классический пример на 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.
}
}
Я думаю, что весь смысл в том, что объект дочернего класса можно рассматривать (приведение типов?) Как родительский класс в статическом типизированном языке, таком как Java:
Rectange rectange = new Square();
но в Ruby я не думаю, что это имеет какой-то смысл, то же самое в 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
Я могу всегда проверять класс объекта, используя:
rectange.class
в этом случае, если код в Ruby вернется Square
так что я не буду относиться к этому как Rectange
,
Может ли кто-нибудь объяснить мне смысл применения LSP в динамически типизированном языке, таком как Ruby?
Хотя я до сих пор не знаю, какую проблему может вызвать то, что Square станет дочерью Rectangle. но теперь я учусь говорить, фиолетовый ли это LSP или нет, используя способ:
за square
объект является экземпляром Square
Учебный класс, rectangle
объект является экземпляром Rectangle
учебный класс
width=
это метод в обоих из них
width=
в square
не может быть заменено width=
в rectangle
потому что он не будет устанавливать высоту, как определено в 'квадрат'.
Я не прав с таким образом мышления?
А также я научился использовать фиолетовый контакт метода 'width =' в Rectangle
Класс для анализа этой проблемы:
за width=
в классе "Прямоугольник"
Предпосылка: @width
а также @height
имеет какое-то значение.
postconditon: @width
изменить на новое значение, @height
остаться нетронутым
для 'width =' в Square
учебный класс
предварительное условие: то же, что и выше
postconditon: "@width" меняется на новое значение, @height
изменить на новое значение
по принципу: не требуй больше, обещай не меньше
@height
изменено, поэтому обещание не выполняется, поэтому оно не может быть наследством
Кто-нибудь может дать мне несколько советов о моем способе анализа этой проблемы с помощью DBC
?
1 ответ
LSP по-прежнему применяется, даже в динамически типизированных языках, таких как Ruby. Ваши рассуждения:
Я всегда могу проверить класс объекта с помощью:
rectange.class
в этом случае, если код в Ruby вернется
Square
так что я не буду относиться к этому какRectangle
,
Не относится к Ruby; вы также можете проверить фактический класс переменной в Java. Это не дает "решения" этой проблемы.
Ключевое наблюдение из этого примера заключается в том, что, хотя квадрат является прямоугольником в геометрии, Square
не является Rectangle
с точки зрения ООП - Square
поведение несовместимо с Rectangle
,