digital-garden/dev/architecture/Liskov Substitution Principle.md

82 lines
4.7 KiB
Markdown
Raw Normal View History

2024-09-27 20:25:32 +03:00
---
aliases:
- LSP
- Принцип подстановки Барбары Лисков
tags:
- maturity/🌱
date: 2024-09-27
---
Принцип подстановки Лисков (Liskov Substitution Principle, LSP) утверждает, что ==объекты подклассов должны быть взаимозаменяемы с объектами базового класса без изменения поведения программы==. Это означает, что ==подклассы не должны нарушать контракт базового класса или изменять его логику==. LSP является третьим принципом в набор[[SOLID|е SOL]]ID и играет ключевую роль в создании устойчивой и понятной иерархии классов.
2024-09-27 20:25:32 +03:00
**Чтобы соответствовать LSP:**
- Подклассы должны расширять функциональность базового класса, не изменяя его поведение.
- [[Контракт взаимодействия|Контракты]], задаваемые базовыми классами, должны строго соблюдаться.
- Следует избегать переопределения методов, если это изменяет их ожидаемое поведение.
**Преимущества соблюдения LSP:**
1. **Предсказуемость:** Код, использующий базовый класс, будет работать одинаково независимо от того, какие подклассы используются.
2. **Упрощение тестирования:** Система становится менее подверженной ошибкам, так как базовый контракт всегда соблюдается.
3. **Гибкость и масштабируемость:** Добавление новых подклассов не требует модификации существующего кода, если соблюден принцип LSP.
4. **Улучшенная читаемость:** Четкое разделение обязанностей между базовыми и дочерними классами упрощает понимание системы.
## Пример нарушения LSP
Рассмотрим иерархию классов для птиц:
2024-09-27 20:25:32 +03:00
```java
public class Bird {
public void fly() {
// Логика полета
System.out.println("I can fly!");
2024-09-27 20:25:32 +03:00
}
}
public class Penguin extends Bird {
@Override
public void fly() {
// Пингвин не может летать — нарушение LSP
throw new UnsupportedOperationException("Penguins cannot fly");
}
}
```
В данном случае класс `Penguin` нарушает контракт базового класса `Bird`. Код, который ожидает, что любой объект типа `Bird` может летать, перестанет работать корректно при использовании `Penguin`. Это ведет к непредсказуемому поведению программы и увеличивает сложность сопровождения.
Для устранения нарушения следует пересмотреть иерархию классов, чтобы явно выделить летающих и нелетающих птиц:
```java
public abstract class Bird {
// Общие свойства и методы для всех птиц
}
public interface Flyable {
void fly();
}
public class FlyingBird extends Bird implements Flyable {
@Override
public void fly() {
// Реализация полета
System.out.println("I can fly!");
2024-09-27 20:25:32 +03:00
}
}
public class Penguin extends Bird {
// Пингвин остается нелетающей птицей
}
2024-09-27 20:25:32 +03:00
```
Теперь поведение каждой птицы становится очевидным, и программа корректно работает с летающими и нелетающими птицами, не нарушая LSP.
2024-09-27 20:25:32 +03:00
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**:: [[SOLID]]
**Источник**::
**Создана**:: [[2024-09-27]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->