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