← Назад к вопросам
Как работает декоратор?
2.0 Middle🔥 121 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как работает декоратор (паттерн Decorator)
Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять новые функции к объектам, оборачивая их в специальные классы-обертки. Это альтернатива наследованию с большей гибкостью.
Принцип работы
Декоратор оборачивает исходный объект и выполняет дополнительные действия до, после или вместо вызова методов этого объекта:
// Интерфейс, который будут реализовывать компонент и декораторы
public interface Coffee {
double getPrice();
String getDescription();
}
// Базовый компонент
public class SimpleCoffee implements Coffee {
@Override
public double getPrice() {
return 2.0;
}
@Override
public String getDescription() {
return "Простой кофе";
}
}
// Абстрактный декоратор
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
}
// Конкретные декораторы
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getPrice() {
return coffee.getPrice() + 0.5;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", молоко";
}
}
public class CaramelDecorator extends CoffeeDecorator {
public CaramelDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getPrice() {
return coffee.getPrice() + 0.75;
}
@Override
public String getDescription() {
return coffee.getDescription() + ", карамель";
}
}
Использование
// Создаем простой кофе
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription()); // "Простой кофе"
System.out.println(coffee.getPrice()); // 2.0
// Добавляем молоко
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription()); // "Простой кофе, молоко"
System.out.println(coffee.getPrice()); // 2.5
// Добавляем карамель
coffee = new CaramelDecorator(coffee);
System.out.println(coffee.getDescription()); // "Простой кофе, молоко, карамель"
System.out.println(coffee.getPrice()); // 3.25
Реальные примеры в Java
1. I/O потоки (классический пример)
FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
// dis оборачивает bis, который оборачивает fis
// Каждый слой добавляет функциональность
2. Spring Framework
@Configuration
public class CacheConfig {
@Bean
public UserService userService(UserRepository repo, CacheManager cache) {
return new CachedUserService(new UserServiceImpl(repo), cache);
}
}
3. Аннотации в Java (как декораторы метаданных)
@Transactional
@Cacheable("users")
@Validated
public User getUser(Long id) {
// Метод украшен аннотациями, которые добавляют функциональность
}
Преимущества и недостатки
Преимущества:
- Гибкость — можно комбинировать декораторы в любом порядке
- Расширяемость — добавлять новые функции без изменения исходного класса
- Альтернатива наследованию — избегаем explosion of classes
- Соответствие SRP — каждый класс отвечает за одну функцию
Недостатки:
- Усложнение кода — большое количество мелких классов
- Сложность отладки — много слоев оборачивания
- Порядок декораторов может быть важен
Отличие от наследования
Декоратор предпочтительнее наследования, когда нужна динамическая комбинация функций:
// ❌ Наследование ведет к explosion of classes
class CoffeeWithMilk extends SimpleCoffee { }
class CoffeeWithMilkAndCaramel extends CoffeeWithMilk { }
class CoffeeWithCaramel extends SimpleCoffee { }
// ... и комбинаций становится экспоненциально много
// ✅ Декоратор — гибкое решение
Coffee coffee = new CaramelDecorator(new MilkDecorator(new SimpleCoffee()));
Декоратор — это мощный паттерн для расширения функциональности без модификации исходного кода.