В чём суть принципа подстановки Барбары Лисков (LSP)?

«В чём суть принципа подстановки Барбары Лисков (LSP)?» — вопрос из категории ООП, который задают на 22% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Принцип подстановки Лисков (Liskov Substitution Principle, LSP) — один из принципов SOLID. Он гласит: объекты производного класса должны быть заменяемы на объекты базового класса без нарушения корректности программы.

Проще говоря: Если у вас есть функция, работающая с базовым классом, то вы должны иметь возможность передать ей любой его подкласс, и программа останется работоспособной.

Нарушение LSP (классический пример «Прямоугольник-Квадрат»):

class Rectangle {
    var width: Double = 0
    var height: Double = 0

    var area: Double { width * height }
}

class Square: Rectangle {
    override var width: Double {
        didSet { height = width } // Побочный эффект: изменение width меняет height
    }
    override var height: Double {
        didSet { width = height }
    }
}

func resizeRectangle(_ rectangle: Rectangle) {
    rectangle.width = 5
    rectangle.height = 4
    print("Ожидаемая площадь: 20. Фактическая: (rectangle.area)")
}

let square = Square()
resizeRectangle(square) // Напечатает: Ожидаемая площадь: 20. Фактическая: 16.0
// Поведение изменилось! Это нарушение LSP.

Следствия и правила LSP:

  • Предусловия (требования к входным данным) в подклассе не могут быть строже.
  • Постусловия (гарантии на выходе) в подклассе не могут быть слабее.
  • Инварианты базового класса (условия, всегда истинные) должны сохраняться в подклассе.
  • Подкласс не должен генерировать новых типов исключений, не описанных в базовом классе.

Цель: Создавать корректные иерархии наследования, где подтипы являются настоящими специализациями базового типа, а не просто имеют схожий код.