Карта / ООП / LSP, композиция vs наследование

LSP, композиция vs наследование

LSP (принцип подстановки Лисков) — наследник должен полностью заменять родителя, не ломая логику программы. Если код работает с Animal, он обязан так же корректно работать с любым Dog extends Animal, без сюрпризов.

Классический пример нарушения — «Квадрат не должен наследоваться от Прямоугольника»:

class Rectangle {
    int width, height;
    void setWidth(int w) { width = w; }
    void setHeight(int h) { height = h; }
}

class Square extends Rectangle {
    void setWidth(int w) { width = w; height = w; }   // ломает ожидания!
    void setHeight(int h) { width = h; height = h; }
}

Код, который ожидает, что setWidth меняет только ширину прямоугольника, сломается на Square — это и есть нарушение LSP: наследник изменил поведение, а не просто расширил его.

Копнуть глубже

Композиция vs наследование — что выбрать. Наследование — это связь «является» (Dog is a Animal), композиция — связь «содержит» (Car has a Engine):

// Наследование: Car IS-A Vehicle
class Car extends Vehicle { ... }

// Композиция: Car HAS-A Engine
class Car {
    private Engine engine;   // Car содержит Engine, а не "является" им
}

Правило индустрии: «предпочитай композицию наследованию». Наследование жёстко связывает классы навсегда (наследник зависит от всех деталей реализации родителя), а композицию легко поменять в рантайме — просто подставить другой объект.

Под капотом

Почему наследование считается «хрупким» (fragile base class problem): изменение родительского класса может незаметно сломать всех наследников, даже если ты не трогал их код напрямую. Метод родителя, на который никто не рассчитывал как на «расширяемый», может оказаться переопределён в самых неожиданных местах — и любое изменение его поведения каскадом ломает иерархию.

Композиция этой проблемы не имеет: объект знает только публичный интерфейс того, что он использует, а не его внутреннее устройство — изменения внутри не пробивают эту границу.

🎤 Закрыл тему, если можешь объяснить:
• что такое LSP и пример его нарушения (квадрат-прямоугольник);
• чем композиция отличается от наследования и почему её часто предпочитают (если дошёл до 2-го слоя).