← Назад к вопросам

Приведи пример, который иллюстрирует Liskov Substitution Principle

2.0 Middle🔥 72 комментариев
#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример, иллюстрирующий принцип подстановки Лисков (LSP)

Принцип подстановки Лисков (LSP) — это третий из пяти принципов SOLID, который гласит, что объекты базового класса должны быть заменяемы объектами его подклассов без изменения корректности программы. Другими словами, подклассы должны дополнять, а не нарушать поведение базового класса.

Классический пример нарушения LSP

Рассмотрим пример с геометрическими фигурами, где нарушение LSP приводит к проблемам в логике программы.

// Базовый класс Прямоугольник
class Rectangle {
    protected int width;
    protected int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getArea() {
        return width * height;
    }
}

// Подкласс Квадрат, который наследуется от Прямоугольника
class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        this.width = width;
        this.height = width; // Нарушение: изменение высоты при установке ширины
    }

    @Override
    public void setHeight(int height) {
        this.height = height;
        this.width = height; // Нарушение: изменение ширины при установке высоты
    }
}

Проблема нарушения LSP

В этом примере Квадрат является подклассом Прямоугольника, но изменяет его поведение: при установке ширины или высоты квадрат изменяет оба измерения. Это приводит к ошибкам, когда код ожидает, что прямоугольник и квадрат ведут себя одинаково.

public class Main {
    public static void main(String[] args) {
        Rectangle rectangle = new Square();
        rectangle.setWidth(5);
        rectangle.setHeight(10);
        
        // Ожидаемая площадь: 5 * 10 = 50
        // Реальная площадь для Square: 10 * 10 = 100
        System.out.println("Area: " + rectangle.getArea()); // Вывод: 100 (ошибка!)
    }
}

Здесь нарушается LSP, потому что Square не может быть заменен на Rectangle без изменения корректности программы: логика расчета площади ломается.

Исправленный пример с соблюдением LSP

Чтобы соблюсти LSP, нужно пересмотреть иерархию классов. Один из подходов — создать общий абстрактный класс или интерфейс для фигур, а затем реализовать отдельные классы для прямоугольника и квадрата.

// Абстрактный класс или интерфейс для геометрических фигур
interface Shape {
    int getArea();
}

// Класс Прямоугольник, реализующий интерфейс Shape
class Rectangle implements Shape {
    private int width;
    private int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public int getArea() {
        return width * height;
    }
}

// Класс Квадрат, реализующий интерфейс Shape
class Square implements Shape {
    private int side;

    public Square(int side) {
        this.side = side;
    }

    @Override
    public int getArea() {
        return side * side;
    }
}

Преимущества соблюдения LSP

  1. Корректность программы: Теперь Square и Rectangle могут использоваться взаимозаменяемо через интерфейс Shape без нарушения логики.
  2. Гибкость кода: Можно легко добавлять новые фигуры (например, Circle), реализующие интерфейс Shape.
  3. Упрощение тестирования: Код, работающий с Shape, не зависит от конкретных реализаций, что упрощает модульное тестирование.

Пример использования исправленной иерархии:

public class Main {
    public static void main(String[] args) {
        Shape rectangle = new Rectangle(5, 10);
        Shape square = new Square(5);

        System.out.println("Rectangle area: " + rectangle.getArea()); // 50
        System.out.println("Square area: " + square.getArea());       // 25

        // Оба объекта могут быть обработаны единообразно
        printArea(rectangle);
        printArea(square);
    }

    public static void printArea(Shape shape) {
        System.out.println("Shape area: " + shape.getArea());
    }
}

Вывод

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

Приведи пример, который иллюстрирует Liskov Substitution Principle | PrepBro