Нарушение принципа подстановки Лискова

Как этот пример ниже нарушает принцип подстановки Лискова? Я до сих пор не могу разобраться с этим. Мне кажется, это нормально с точки зрения иерархии в PHP ООП.

// 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

Результаты обоих верны.

Итак, как этот код должен быть написан так, чтобы он не нарушал принцип подстановки Лискова?

1

Решение

От Принцип замещения Лискова:

Типичным примером, который нарушает LSP, является класс Square, который выводит
из класса Rectangle, предполагая, что методы getter и setter существуют для
как ширина, так и высота. Класс Square всегда предполагает, что ширина
равен высоте. Если объект Square используется в контексте
где ожидается прямоугольник, может произойти неожиданное поведение, потому что
размеры квадрата не могут (или скорее не должны) быть изменены
независимо. Эта проблема не может быть легко решена: если мы можем изменить
методы сеттера в классе Square, чтобы они сохраняли
Квадратный инвариант (т.е. сохранить размеры равными), то эти методы
ослабит (нарушит) постусловия для сеттеров Rectangle,
которые утверждают, что размеры могут быть изменены независимо.
Нарушения
LSP, как этот, может или не может быть проблемой на практике,
в зависимости от постусловий или инвариантов, которые на самом деле
ожидается код, который использует классы, нарушающие LSP. Изменчивость это
ключевой вопрос здесь. Если бы у Square и Rectangle были только методы-получатели (т.е.
это были неизменяемые объекты), тогда никакого нарушения LSP не могло произойти.

Так что если вы избавляетесь от сеттеров, ваше решение больше не нарушает LSV.

3

Другие решения

setWidth и setHeight определены в родительском классе, и в соответствии с принципом подстановки Лискова вы не должны изменять поведение родительского класса в производных классах. когда Square наследует от Rectangle, это делает Square производным классом, что означает, что вы не должны изменять ни один из этих двух методов (setWith и setHeight), изначально определенных в классе Rectangle.

Нарушение принципа подстановки Лискова приводит к нежелательным последствиям. Если иерархия классов растет, становится все сложнее узнать о поведении дочерних классов. Во-вторых, модульные тесты для суперкласса никогда не будут успешными для подкласса. Код, который использует ваш тип, должен иметь четкие знания о внутренней работе производных типов, чтобы трактовать их по-разному.

Я написал пост, объясняющий этот принцип и последствия его нарушения.

http://isaacjarquin.github.io/software/2016/09/27/solid-liskov-substitution-principle.html

0

По вопросам рекламы [email protected]