107 lines
5.4 KiB
Markdown
107 lines
5.4 KiB
Markdown
---
|
||
aliases:
|
||
- Open/Closed Principle
|
||
- OCP
|
||
- Принцип открытости/закрытости
|
||
tags:
|
||
- maturity/🌱
|
||
date: 2024-09-27
|
||
---
|
||
Классы и модули должны быть **открыты для расширения, но закрыты для модификации**. Это означает, что функциональность можно добавлять без изменения существующего кода. Такой подход позволяет минимизировать риск возникновения ошибок в уже работающей системе при внедрении новых функций. **Принцип открытости/закрытости (Open-Closed Principle, OCP)** является вторым из пяти [[SOLID]]-принципов и способствует созданию гибкой и поддерживаемой архитектуры.
|
||
|
||
Обычно для реализации принципа используются:
|
||
- **Интерфейсы** или **абстрактные классы**, которые задают общую структуру поведения.
|
||
- [[Полиморфизм]], позволяющий создавать новые реализации без изменения базового кода.
|
||
|
||
Следование OCP снижает [[связанность]] модулей, делает код проще в тестировании и облегчает внедрение новых функций.
|
||
|
||
**Преимущества соблюдения OCP:**
|
||
1. **Гибкость кода:** Добавление нового функционала не требует изменений существующего кода, что снижает риск ошибок.
|
||
2. **Улучшенная тестируемость:** Изолированные реализации проще тестировать независимо друг от друга.
|
||
3. **Снижение связанности:** Код становится более модульным, и изменения в одной части системы не затрагивают другие.
|
||
4. **Поддерживаемость:** Разработчики могут легко добавлять новые возможности без угрозы сломать существующий функционал.
|
||
|
||
## Пример нарушения OCP
|
||
Рассмотрим класс, который обрабатывает оплату, поддерживая только один способ оплаты через кредитную карту:
|
||
|
||
```java
|
||
public class PaymentProcessor {
|
||
public void processPayment(String type, double amount) {
|
||
if (type.equals("credit_card")) {
|
||
// Логика оплаты через кредитную карту
|
||
}
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
Если требуется добавить поддержку нового способа оплаты, например, PayPal, придется модифицировать метод `processPayment`:
|
||
|
||
```java
|
||
public class PaymentProcessor {
|
||
public void processPayment(String type, double amount) {
|
||
if (type.equals("credit_card")) {
|
||
// Логика оплаты через кредитную карту
|
||
} else if (type.equals("paypal")) {
|
||
// Логика оплаты через PayPal
|
||
}
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
Такой подход нарушает OCP, так как для добавления нового функционала приходится изменять уже существующий код. Это увеличивает риск ошибок и затрудняет сопровождение.
|
||
|
||
Используем интерфейсы для реализации разных способов оплаты:
|
||
|
||
```java
|
||
public interface PaymentMethod {
|
||
void pay(double amount);
|
||
}
|
||
|
||
public class CreditCardPayment implements PaymentMethod {
|
||
@Override
|
||
public void pay(double amount) {
|
||
// Оплата через кредитную карту
|
||
}
|
||
}
|
||
|
||
public class PayPalPayment implements PaymentMethod {
|
||
@Override
|
||
public void pay(double amount) {
|
||
// Оплата через PayPal
|
||
}
|
||
}
|
||
```
|
||
|
||
Теперь процессор оплаты будет работать с интерфейсом `PaymentMethod`, не завися от конкретных реализаций:
|
||
|
||
```java
|
||
public class PaymentProcessor {
|
||
private PaymentMethod paymentMethod;
|
||
|
||
public PaymentProcessor(PaymentMethod paymentMethod) {
|
||
this.paymentMethod = paymentMethod;
|
||
}
|
||
|
||
public void processPayment(double amount) {
|
||
paymentMethod.pay(amount);
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
Для добавления нового способа оплаты достаточно создать новую реализацию `PaymentMethod`, не изменяя код процессора.
|
||
***
|
||
## Мета информация
|
||
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
|
||
**Родитель**:: [[SOLID|SOLID]]
|
||
**Источник**::
|
||
**Создана**:: [[2024-09-27]]
|
||
**Автор**::
|
||
### Дополнительные материалы
|
||
-
|
||
|
||
### Дочерние заметки
|
||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|