3. LSP (Liskov substitution principle) - Принцип подстановки Барбары Лисков

Принцип подстановки Барбары Лисков (англ. Liskov Substitution Principle, LSP) в объектно-ориентированном программировании является специфичным определением подтипа, предложенным Барбарой Лисков в 1987 году на конференции в основном докладе под названием Абстракция данных и иерархия.

В последующей статье Лисков кратко сформулировала свой принцип следующим образом:

Пусть q(x) является свойством, верным относительно объектовx некоторого типаT. Тогдаq(y) также должно быть верным для объектовy типаS, гдеS является подтипом типаT.

Роберт С. Мартин определил этот принцип так:

Функции, которые используют базовый тип, должны иметь возможность использовать подтипы базового типа не зная об этом.

Таким образом, идея Лисков о «подтипе» даёт определение понятия замещения — если S является подтипом T, тогда объекты типа T в программе могут быть замещены объектами типа S без каких-либо изменений желательных свойств этой программы (например, корректность).

Этот принцип является важнейшим критерием для оценки качества принимаемых решений при построении иерархий наследования. Сформулировать его можно в виде простого правила: тип S будет подтипом Т тогда и только тогда, когда каждому объекту oS типа S соответствует некий объект oT типа T таким образом, что для всех программ P, реализованных в терминах T, поведение P не будет меняться, если oT заменить на oS.

Более простыми словами можно сказать, что поведение наследуемых классов не должно противоречить поведению, заданному базовым классом, то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа.

Саттер и Александреску в своём руководстве по использованию Си++ для выражения этого принципа также используют фразу «подкласс не должен требовать от вызывающего кода больше, чем базовый класс, и не должен предоставлять вызывающему коду меньше, чем базовый класс». По мнению данных авторов, публичное наследование в Си++ можно употреблять только тогда, когда оно удовлетворяет принципу Лисков. Приватное наследование, по их же мнению, дозволено использовать для доступа к protected части базы и перекрытия виртуальных методов. В любом же ином случае, то есть для всего лишь повторного использования кода из базы, наследование применять нельзя.

Возвращаясь к нашему классу AreaCalculator, пусть у нас будет класс VolumeCalculator, который его наследует:

class VolumeCalculator extends AreaCalulator {
     public function __construct($shapes = array()) {
         parent::__construct($shapes);
     }
 
     public function sum() {
         // logic to calculate the volumes and then return and array of output
         return array($summedData);
     }
}

И класс SumCalculatorOutputter:

class SumCalculatorOutputter {
     protected $calculator;
 
     public function __constructor(AreaCalculator $calculator) {
         $this->calculator = $calculator;
     }
 
     public function JSON() {
         $data = array(
         'sum' => $this->calculator->sum();
     );
 
         return json_encode($data);
     }
 
     public function HTML() {
         return implode('', array(
             '<h1>',
         'Sum of the areas of provided shapes: ',
         $this->calculator->sum(),
         '</h1>'
         ));
     }
}

Попробуем запустить пример так:

$areas = new AreaCalculator($shapes);
$volumes = new AreaCalculator($solidShapes);
 
$output = new SumCalculatorOutputter($areas);
$output2 = new SumCalculatorOutputter($volumes);

В программе не происходит ошибок, пока мы не вызовем HTML метод объекта $output2 - мы получаем E_NOTICE предупреждение о том, что код программы пытается преобразовать массив в строку.

Чтобы это исправить мы должны возвращать данные вместо массива:

public function sum() {
     // logic to calculate the volumes and then return and array of output
     return $summedData;
}

Выходные данные имеют тип float, double или integer.

Теги: Solid, Lsp, Liskov substitution principle, Принцип подстановки барбары лисков


Похожие статьи

4. ISP (Interface segregation principle) - Принцип разделения интерфейса

2. OCP (Open/closed principle) - Принцип открытости/закрытости

5. DIP (Dependency inversion principle) - Принцип инверсии зависимостей

1. SPR (Single responsibility principle) - Принцип единственной обязанности