mko*_*mko 6 ruby oop liskov-substitution-principle
我已经阅读了一些关于使Square成为Rectangle类的继承类的做法的一些文章,这说明它违反了LSP(Liskov替换原则).我仍然没有得到它,我在Ruby中做了一个示例代码:
class Rectangle
attr_accessor :width, :height
def initialize(width, height)
@width = width
@height = height
end
end
class Square < Rectangle
def initialize(length)
super(length, length)
end
def width=(number)
super(number)
@height = number
end
def height=(number)
super(number)
@width = number
end
end
s = Square.new(100)
s.width = 50
puts s.height
Run Code Online (Sandbox Code Playgroud)
谁能告诉我它有什么问题?
我并不总是热衷于 Liskov,因为它似乎限制了基于行为而不是“本质”的继承的用途。在我看来,继承始终意味着一种“是一种”关系,而不是一种“行为完全相同”的关系。
话虽如此,维基百科文章使用您的确切示例详细说明了为什么有些人认为这是不好的:
违反 LSP 的一个典型示例是从 Rectangle 类派生的 Square 类,假设宽度和高度都存在 getter 和 setter 方法。
Square 类始终假设宽度与高度相等。如果 Square 对象在需要 Rectangle 的上下文中使用,则可能会发生意外行为,因为 Square 的尺寸不能(或者更确切地说不应该)独立修改。
这个问题不容易解决:如果我们可以修改 Square 类中的 setter 方法,使它们保留 Square 不变性(即保持尺寸相等),那么这些方法将削弱(违反) Rectangle setter 的后置条件,这会导致说明尺寸可以独立修改。
因此,将您的代码与等效Rectangle代码一起查看:
s = Square.new(100) r = Rectangle.new(100,100)
s.width = 50 r.width = 50
puts s.height puts r.height
Run Code Online (Sandbox Code Playgroud)
左侧的输出为 50,右侧的输出为 100。
但是,在我看来,这是这篇文章的重要部分:
像这样的违反 LSP 的行为在实践中可能会或可能不会成为问题,具体取决于使用违反 LSP 的类的代码实际期望的后置条件或不变量。
换句话说,假设代码使用类的代码理解该行为,就不会有问题。
底线是,正方形是矩形的真子集,对于矩形的定义足够宽松:-)