← Назад к вопросам
Приведи пример использования паттерна декоратор
3.0 Senior🔥 11 комментариев
#Docker, Kubernetes и DevOps
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерн Декоратор (Decorator Pattern)
Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять новую функциональность к объектам, оборачивая их в специальные объекты-обёртки. Это альтернатива наследованию, которая работает более гибко.
Зачем нужен декоратор
Представь: у тебя есть класс Coffee (кофе). Ты можешь:
- Добавить молоко
- Добавить сахар
- Добавить карамель
- Комбинировать все вместе
Если использовать наследование, создастся взрыв классов: CoffeeWithMilk, CoffeeWithSugar, CoffeeWithMilkAndSugar, и т.д. Декоратор решает эту проблему элегантно.
Пример с кодом
// Базовый интерфейс
public interface Beverage {
double getCost();
String getDescription();
}
// Конкретная реализация
public class Coffee implements Beverage {
@Override
public double getCost() {
return 2.0; // $2
}
@Override
public String getDescription() {
return "Coffee";
}
}
// Абстрактный декоратор
public abstract class BeverageDecorator implements Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage) {
this.beverage = beverage;
}
}
// Конкретный декоратор 1: Молоко
public class MilkDecorator extends BeverageDecorator {
public MilkDecorator(Beverage beverage) {
super(beverage);
}
@Override
public double getCost() {
return beverage.getCost() + 0.5;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
}
// Конкретный декоратор 2: Сахар
public class SugarDecorator extends BeverageDecorator {
public SugarDecorator(Beverage beverage) {
super(beverage);
}
@Override
public double getCost() {
return beverage.getCost() + 0.25;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Sugar";
}
}
// Конкретный декоратор 3: Ванильный сироп
public class VanillaSyrupDecorator extends BeverageDecorator {
public VanillaSyrupDecorator(Beverage beverage) {
super(beverage);
}
@Override
public double getCost() {
return beverage.getCost() + 0.75;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Vanilla Syrup";
}
}
Использование
public class CoffeeShop {
public static void main(String[] args) {
// Просто кофе
Beverage beverage1 = new Coffee();
System.out.println(beverage1.getDescription() + " - \$" + beverage1.getCost());
// Вывод: Coffee - $2.0
// Кофе с молоком
Beverage beverage2 = new MilkDecorator(new Coffee());
System.out.println(beverage2.getDescription() + " - \$" + beverage2.getCost());
// Вывод: Coffee, Milk - $2.5
// Кофе с молоком и сахаром
Beverage beverage3 = new SugarDecorator(new MilkDecorator(new Coffee()));
System.out.println(beverage3.getDescription() + " - \$" + beverage3.getCost());
// Вывод: Coffee, Milk, Sugar - $2.75
// Кофе с молоком, сахаром и ванильным сиропом
Beverage beverage4 = new VanillaSyrupDecorator(
new SugarDecorator(
new MilkDecorator(new Coffee())
)
);
System.out.println(beverage4.getDescription() + " - \$" + beverage4.getCost());
// Вывод: Coffee, Milk, Sugar, Vanilla Syrup - $3.5
}
}
Преимущества паттерна
- Гибкость: добавляй функции динамически в любое время
- Комбинируемость: комбинируй декораторы в любом порядке
- Не нарушает открыто-закрытый принцип (OCP): расширяем функциональность без изменения исходного класса
- Избегаем взрыва классов: вместо N×M комбинаций у нас есть модульный подход
Реальные примеры в Java
java.ioпакет:BufferedInputStream,DataInputStream— это декораторы дляInputStream- Spring:
@Transactional,@Cacheable— декораторы функциональности - Подготовка напитков в кофейне: как в нашем примере
Недостатки
- Может привести к множеству маленьких классов
- Порядок декораторов иногда имеет значение
- Сложнее отладить длинные цепочки декораторов
Вывод: Декоратор — мощный паттерн для добавления функциональности без наследования. Используй его, когда нужно комбинировать поведение гибко.