以下这个例子如何违反Liskov的替代原则?我仍然无法理解它。对于我来说,在PHP OOP中的层次结构似乎没问题。
// Violation of Likov's Substitution Principle
class Rectangle
{
protected $width;
protected $height;
public function setWidth($width){
$this->width = $width;
}
public function setHeight($height){
$this->height = $height;
}
public function getWidth(){
return $width;
}
public function getHeight(){
return $height;
}
public function getArea(){
return $this->width * $this->height;
}
}
class Square extends Rectangle
{
public function setWidth($width){
$this->width = $width;
$this->height = $width;
}
public function setHeight($height){
$this->width = $height;
$this->height = $height;
}
}
用法:
$Rectangle = new Rectangle();
$Rectangle->setWidth(5);
$Rectangle->setHeight(10);
echo $Rectangle->getArea(); // 50 --> correct
另:
$Rectangle = new Square();
$Rectangle->setWidth(5);
$Rectangle->setHeight(10);
echo $Rectangle->getArea(); // 100 --> correct
两者的重复是正确的。
那么,这段代码应该如何编写,以免违反Liskov的替代原则?
答案 0 :(得分:3)
来自Liskov Substitution Principle:
违反LSP的典型示例是派生的Square类 来自Rectangle类,假设存在getter和setter方法 宽度和高度。 Square类总是假设宽度 等于高度。如果在上下文中使用Square对象 在期望Rectangle的地方,可能会发生意外行为,因为 Square的尺寸不能(或者不应该)被修改 独立。 这个问题不容易修复:如果我们可以修改 Square类中的setter方法,以便它们保留 方形不变(即保持尺寸相等),然后是这些方法 会削弱(违反)矩形制定者的后置条件, 说明维度可以独立修改。违规 像这样的LSP,在实践中可能是也可能不是问题, 取决于实际的后置条件或不变量 期望由使用违反LSP的类的代码。可变性是一个 关键问题在这里。如果Square和Rectangle只有getter方法(即 它们是不可变对象),然后不会发生违反LSP的行为。
因此,如果你摆脱了setter,你的解决方案不再违反LSV。
答案 1 :(得分:0)
setWidth和setHeight已在父类中定义,并且根据Liskov替换原则,您不应修改派生类中父类的行为。当Square从Rectangle继承时,它使Square成为一个派生类,这意味着你不应该修改最初在Rectangle类中定义的那两个方法(setWith和setHeight)中的任何一个。
违反Liskov替代原则会产生不良影响。如果类层次结构增长,那么了解子类的行为将变得越来越复杂。其次,超类的单元测试对于子类永远不会成功。使用您的类型的代码必须明确了解派生类型的内部工作方式,以区别对待它们
我写了一篇文章解释了这个原则以及违反原则的后果。
http://isaacjarquin.github.io/software/2016/09/27/solid-liskov-substitution-principle.html