← Назад к вопросам
Приведи пример нарушения принципа Барбары Лисков
2.0 Middle🔥 141 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Нарушение принципа Барбары Лисков (Liskov Substitution Principle)
Принцип подстановки Барбары Лисков (LSP) — один из ключевых принципов SOLID, который гласит: объекты подклассов должны корректно заменять объекты базовых классов без нарушения работы программы.
Классический пример нарушения: Квадрат и Прямоугольник
Это самый известный пример нарушения LSP:
public 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;
}
}
public 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 AreaCalculator {
public int calculateArea(Rectangle rect) {
rect.setWidth(5);
rect.setHeight(4);
int area = rect.getArea();
return area;
}
}
Rectangle rect = new Rectangle();
AreaCalculator calc = new AreaCalculator();
System.out.println(calc.calculateArea(rect)); // 20
Rectangle square = new Square();
System.out.println(calc.calculateArea(square)); // 16 - НЕОЖИДАННЫЙ РЕЗУЛЬТАТ!
Проблема: Square нельзя безопасно использовать вместо Rectangle, потому что его поведение нарушает контракт базового класса.
Другие примеры нарушения LSP
Птица может летать? Нет!
public abstract class Bird {
public abstract void fly();
}
public class Eagle extends Bird {
@Override
public void fly() {
System.out.println("Орёл летит");
}
}
public class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Пингвины не летают!");
}
}
public void makeBirdFly(Bird bird) {
bird.fly();
}
Нарушение: Не все птицы летают. Пингвин не должен наследовать Bird.
Выброс неожиданного исключения
public class PaymentProcessor {
public void processPayment(int amount) {
System.out.println("Платёж обработан: " + amount);
}
}
public class SpecialPaymentProcessor extends PaymentProcessor {
@Override
public void processPayment(int amount) {
if (amount < 100) {
throw new IllegalArgumentException("Минимальная сумма 100");
}
super.processPayment(amount);
}
}
PaymentProcessor processor = new SpecialPaymentProcessor();
processor.processPayment(50); // Выбросится неожиданное исключение!
Усиление предусловий
public class Logger {
public void log(String message) {
if (message != null) {
System.out.println(message);
}
}
}
public class StrictLogger extends Logger {
@Override
public void log(String message) {
if (message == null || message.isEmpty()) {
throw new IllegalArgumentException("Не может быть пусто");
}
System.out.println(message);
}
}
Logger logger = new StrictLogger();
logger.log(""); // Выбросится исключение!
Как исправить нарушения LSP?
Решение 1: Правильная иерархия классов
public abstract class Shape {
abstract int getArea();
}
public class Rectangle extends 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;
}
}
public class Square extends Shape {
private int side;
public Square(int side) {
this.side = side;
}
@Override
public int getArea() {
return side * side;
}
}
Решение 2: Разделение интерфейсов
public interface FlyingAnimal {
void fly();
}
public interface SwimmingAnimal {
void swim();
}
public class Eagle implements FlyingAnimal {
@Override
public void fly() {
System.out.println("Орёл летит");
}
}
public class Penguin implements SwimmingAnimal {
@Override
public void swim() {
System.out.println("Пингвин плывёт");
}
}
Ключевые признаки нарушения LSP
- Проверка типов:
if (obj instanceof SpecificClass) - Выброс неожиданных исключений в подклассе
- Усиление предусловий или ослабление постусловий
- Поведение подкласса отличается от базового в неожиданных ситуациях
Лучшие практики
- Контракт базового класса — строго соблюдай в подклассах
- Не выбрасывай новые исключения — только те, что объявлены в базовом классе
- Не усиливай предусловия — не добавляй новые проверки
- Не ослабляй постусловия — не снижай гарантии результата
- Используй интерфейсы — для логически связанных операций
Принцип LSP обеспечивает надежность кода и упрощает его тестирование.