Ответ
Принцип подстановки Лисков (LSP) — третий принцип SOLID. Он гласит: объекты в программе должны быть заменяемы экземплярами их подтипов (наследников) без изменения корректности этой программы.
Проще говоря: Если у вас есть функция, работающая с классом Родитель, то она должна безошибочно работать и с любым классом Ребёнок, унаследованным от Родителя. Наследник не должен нарушать контракт базового класса.
Ключевые аспекты контракта:
- Предусловия (требования к входным данным) не могут быть усилены в подклассе.
- Постусловия (гарантии на выходе) не могут быть ослаблены в подклассе.
- Инварианты (условия, истинные на протяжении всей жизни объекта) должны сохраняться.
Классический пример нарушения LSP:
// Базовый класс, предполагающий, что все птицы летают.
class Bird {
public function fly(): int {
return $this->airSpeedVelocity; // Возвращает скорость полёта
}
}
// Подкласс, нарушающий контракт. Пингвин не летает.
class Penguin extends Bird {
public function fly(): int {
throw new RuntimeException('Penguins cannot fly!'); // Усилено предусловие (теперь нужно НЕ летать)
// или return 0; // Ослаблено постусловие (скорость полёта не имеет смысла)
}
}
// Функция, рассчитанная на работу с Bird.
function traverseForest(array $birds) {
foreach ($birds as $bird) {
$speed = $bird->fly(); // Для Penguin выбросится исключение, программа сломается.
// ...
}
}
Как исправить, следуя LSP: Нужно пересмотреть иерархию наследования, чтобы она отражала реальные возможности объектов.
// Более точная абстракция.
abstract class Bird {
// Общие для всех птиц методы (есть, пить, размножаться)
}
// Интерфейс для способности, а не для сущности.
interface Flyable {
public function fly(): int;
}
class Sparrow extends Bird implements Flyable {
public function fly(): int {
return 15; // OK
}
}
class Penguin extends Bird {
public function swim(): int {
return 10; // OK, пингвин плавает
}
}
// Теперь функция работает только с летающими объектами.
function traverseForest(array $flyableBirds) {
foreach ($flyableBirds as $bird) {
$speed = $bird->fly(); // Гарантированно безопасно
}
}
Соблюдение LSP делает систему устойчивой к изменениям и позволяет безопасно использовать полиморфизм.