Поясните принципы SOLID и приведите конкретные примеры их применения и нарушения в небольшом Java-проекте для управления заказами в интернет-магазине

11 Ноя в 09:34
3 +2
0
Ответы
1
SOLID — это набор из ......... пяти принципов объектно‑ориентированного проектирования, повышающих гибкость и поддерживаемость кода. Ниже кратко о каждом принципе с конкретными примерами (нарушение → исправление) в контексте небольшого Java‑проекта управления заказами.
1) SRP — Single Responsibility Principle (принцип единственной ответственности)
- Суть: класс должен иметь одну причину для изменения — одну ответственность.
- Нарушение (плохой код):
```java
class OrderService {
void placeOrder(Order o) {
double total = calculateTotal(o);
saveToDb(o);
sendConfirmationEmail(o);
logToFile(o);
}
// расчёт, сохранение, отправка писем, логирование — всё в одном классе
}
```
- Исправление (разбиение обязанностей):
```java
class OrderService {
private final OrderRepository repo;
private final NotificationService notifier;
private final DiscountCalculator discount;
void placeOrder(Order o) {
o.setTotal(discount.apply(o));
repo.save(o);
notifier.sendConfirmation(o);
}
}
```
Разделили: OrderRepository, NotificationService, DiscountCalculator — каждая зона ответственности в отдельном классе.
2) OCP — Open/Closed Principle (открыт для расширения, закрыт для модификации)
- Суть: поведение системы можно расширять без изменения существующего кода.
- Нарушение:
```java
class DiscountCalculator {
double apply(Order o) {
if (o.type == OrderType.SEASON) return o.total * 0.9;
if (o.type == OrderType.VIP) return o.total * 0.8;
// при добавлении нового типа — меняем этот класс
}
}
```
- Исправление (использовать полиморфизм/стратегии):
```java
interface DiscountRule { double apply(Order o); }
class VipDiscount implements DiscountRule { public double apply(Order o) { return o.getTotal()*0.8; } }
class SeasonDiscount implements DiscountRule { public double apply(Order o) { return o.getTotal()*0.9; } }
class DiscountCalculator {
private final List rules;
double apply(Order o) {
return rules.stream().reduce(o.getTotal(), (t, r) -> r.apply(o), (a,b)->b);
}
}
```
Новые правила добавляются как новые классы, не трогая существующий код.
3) LSP — Liskov Substitution Principle (принцип подстановки Барбары Лисков)
- Суть: объекты подклассов должны заменять объекты базового класса без нарушения ожидаемого поведения.
- Нарушение:
```java
class Order {
void cancel() { /* отмена */ }
}
class PaidOrder extends Order {
@Override
void cancel() { throw new UnsupportedOperationException("Paid orders can't be canceled"); }
}
// Код, который вызывает cancel() на Order, ломается для PaidOrder
```
- Исправление (разделить интерфейсы/модели):
```java
interface Cancellable { void cancel(); }
class Order { /* общая логика */ }
class CancellableOrder extends Order implements Cancellable { public void cancel() { /* ... */ } }
class PaidOrder extends Order { /* не реализует Cancellable */ }
```
Клиент коду вызывает cancel() только для объектов, реализующих Cancellable, LSP сохраняется.
4) ISP — Interface Segregation Principle (принцип разделения интерфейсов)
- Суть: клиенты не должны зависеть от методов, которыми они не пользуются. Интерфейсы — узкие, ориентированные.
- Нарушение:
```java
interface OrderOperations {
void ship(Order o);
void refund(Order o);
void printInvoice(Order o);
}
class WarehouseService implements OrderOperations {
public void ship(Order o) { /* ok */ }
public void refund(Order o) { throw new UnsupportedOperationException(); } // не нужно, но реализовать надо
public void printInvoice(Order o) { throw new UnsupportedOperationException(); }
}
```
- Исправление (разделить интерфейсы):
```java
interface Shippable { void ship(Order o); }
interface Refundable { void refund(Order o); }
interface InvoicePrintable { void printInvoice(Order o); }
class WarehouseService implements Shippable { public void ship(Order o) { /* ... */ } }
```
Каждый сервис реализует только необходимые методы.
5) DIP — Dependency Inversion Principle (принцип инверсии зависимостей)
- Суть: высокоуровневые модули не должны зависеть от низкоуровневых; оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей; детали — от абстракций.
- Нарушение:
```java
class OrderService {
private final EmailNotifier notifier = new EmailNotifier(); // жёсткая зависимость
void placeOrder(Order o) { notifier.send(o); }
}
```
- Исправление (зависимость от интерфейса, DI):
```java
interface Notifier { void send(Order o); }
class EmailNotifier implements Notifier { public void send(Order o){ /* ... */ } }
class OrderService {
private final Notifier notifier;
OrderService(Notifier notifier) { this.notifier = notifier; } // внедряем зависимость
void placeOrder(Order o) { notifier.send(o); }
}
```
Теперь можно подменять реализацию (Email, SMS, Mock) без изменения OrderService.
Короткие рекомендации при проектировании order‑системы:
- Делите обязанности (SRP): отдельные классы для хранения, оплаты, уведомлений, расчёта скидок.
- Расширяйте через интерфейсы/стратегии (OCP).
- Разделяйте интерфейсы по ролям (ISP).
- Не привязывайтесь к конкретным реализациям; используйте DI/контейнеры (DIP).
- Избегайте подклассов, которые нарушают контракт базового класса; при сомнении выделяйте дополнительные интерфейсы (LSP).
Если нужно, могу привести более развёрнутые Java‑файлы (полные классы) для каждой иллюстрации.
11 Ноя в 10:17
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир