Как работает паттерн проектирования Decorator?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Паттерн Decorator (Декоратор)
Decorator — это структурный паттерн проектирования, который позволяет динамически добавлять новую функциональность к объектам, оборачивая их в декораторы.
Основная идея
Вместо создания новых классов через наследование, мы оборачиваем существующий объект в другой объект (декоратор), добавляя функциональность.
Исходный объект → [Декоратор 1] → [Декоратор 2] → [Декоратор N]
Структура паттерна
// 1. Базовый интерфейс
public interface Component {
void operation();
}
// 2. Конкретный компонент
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("Basic operation");
}
}
// 3. Абстрактный Декоратор
public abstract class Decorator implements Component {
protected Component component; // Композиция!
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation(); // Делегируем базовому компоненту
}
}
// 4. Конкретные декораторы
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("[DecoratorA: Before]");
super.operation(); // Вызовем базовый компонент
System.out.println("[DecoratorA: After]");
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("[DecoratorB: Start]");
super.operation(); // Вызовем базовый компонент
System.out.println("[DecoratorB: End]");
}
}
// Использование
public class DecoratorDemo {
public static void main(String[] args) {
Component basic = new ConcreteComponent();
basic.operation();
// Output: Basic operation
// Оборачиваем в DecoratorA
Component withA = new ConcreteDecoratorA(basic);
withA.operation();
// Output:
// [DecoratorA: Before]
// Basic operation
// [DecoratorA: After]
// Оборачиваем в DecoratorB
Component withAB = new ConcreteDecoratorB(withA);
withAB.operation();
// Output:
// [DecoratorB: Start]
// [DecoratorA: Before]
// Basic operation
// [DecoratorA: After]
// [DecoratorB: End]
}
}
Реальный пример: Компонент UI
// Базовый интерфейс — что может делать компонент
public interface UIComponent {
void render();
}
// Простой текстовый компонент
public class TextComponent implements UIComponent {
private String text;
public TextComponent(String text) {
this.text = text;
}
@Override
public void render() {
System.out.println("Text: " + text);
}
}
// Абстрактный декоратор
public abstract class UIDecorator implements UIComponent {
protected UIComponent component;
public UIDecorator(UIComponent component) {
this.component = component;
}
@Override
public void render() {
component.render();
}
}
// Декоратор добавляет границу
public class BorderDecorator extends UIDecorator {
public BorderDecorator(UIComponent component) {
super(component);
}
@Override
public void render() {
System.out.println("┌─────────────┐");
super.render();
System.out.println("└─────────────┘");
}
}
// Декоратор добавляет фон
public class BackgroundDecorator extends UIDecorator {
private String bgColor;
public BackgroundDecorator(UIComponent component, String bgColor) {
super(component);
this.bgColor = bgColor;
}
@Override
public void render() {
System.out.println("[Background: " + bgColor + "]");
super.render();
System.out.println("[/Background]");
}
}
// Декоратор добавляет тень
public class ShadowDecorator extends UIDecorator {
public ShadowDecorator(UIComponent component) {
super(component);
}
@Override
public void render() {
System.out.println("🎨 Shadow effect");
super.render();
System.out.println("🎨 /Shadow effect");
}
}
// Использование
public class UIDemo {
public static void main(String[] args) {
UIComponent text = new TextComponent("Hello, World!");
// Добавляем границу
UIComponent bordered = new BorderDecorator(text);
// Добавляем фон
UIComponent bgBordered = new BackgroundDecorator(bordered, "blue");
// Добавляем тень
UIComponent final_component = new ShadowDecorator(bgBordered);
final_component.render();
// Output:
// 🎨 Shadow effect
// [Background: blue]
// ┌─────────────┐
// Text: Hello, World!
// └─────────────┘
// [/Background]
// 🎨 /Shadow effect
}
}
Пример: Обработка данных (потоки I/O в Java)
Java Collections и I/O используют Decorator активно!
// Базовый поток
InputStream is = new FileInputStream("data.txt");
// Декоратор — буферизация
InputStream buffered = new BufferedInputStream(is);
// Декоратор — данные + заголовки
InputStream dataIs = new DataInputStream(buffered);
// Все вместе:
DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream("data.txt")
)
);
int number = dis.readInt(); // Читает из цепи декораторов
dis.close();
Пример: Логирование и валидация
// Интерфейс
public interface DataProcessor {
void process(String data);
}
// Базовая обработка
public class SimpleProcessor implements DataProcessor {
@Override
public void process(String data) {
System.out.println("Processing: " + data);
}
}
// Декоратор — логирование
public class LoggingDecorator implements DataProcessor {
private DataProcessor processor;
public LoggingDecorator(DataProcessor processor) {
this.processor = processor;
}
@Override
public void process(String data) {
System.out.println("[LOG] Starting to process: " + data);
long start = System.currentTimeMillis();
processor.process(data);
long duration = System.currentTimeMillis() - start;
System.out.println("[LOG] Completed in " + duration + "ms");
}
}
// Декоратор — валидация
public class ValidationDecorator implements DataProcessor {
private DataProcessor processor;
public ValidationDecorator(DataProcessor processor) {
this.processor = processor;
}
@Override
public void process(String data) {
if (data == null || data.isEmpty()) {
System.out.println("[VALIDATION ERROR] Data is empty!");
return;
}
processor.process(data);
}
}
// Использование
public class ProcessorDemo {
public static void main(String[] args) {
DataProcessor processor = new SimpleProcessor();
// Добавляем валидацию
processor = new ValidationDecorator(processor);
// Добавляем логирование
processor = new LoggingDecorator(processor);
processor.process("Important data");
// Output:
// [LOG] Starting to process: Important data
// [VALIDATION ERROR] Data is not empty
// Processing: Important data
// [LOG] Completed in 5ms
}
}
Преимущества Decorator
✅ Гибкость — добавляй функциональность без изменения класса
✅ Runtime — декораторы применяются во время выполнения
✅ Комбинируемость — можно применить несколько декораторов
✅ SRP — каждый декоратор отвечает за одну функцию
✅ Альтернатива наследованию — вместо Explosion of classes
Недостатки Decorator
❌ Сложность — много маленьких объектов
❌ Порядок важен — порядок декораторов может влиять на результат
❌ Debug сложнее — цепь объектов трудно отследить
Сравнение: Наследование vs Decorator
// ❌ Наследование — Explosion of classes!
public class BorderedBackground {} // Только граница и фон
public class BorderedBackgroundShadow {} // Граница + фон + тень
public class BackgroundShadow {} // Фон + тень
// Комбинаций: 2^n
// ✅ Decorator — гибче
UIComponent c = new TextComponent("Text");
c = new BorderDecorator(c);
c = new BackgroundDecorator(c, "blue");
c = new ShadowDecorator(c);
// Легко комбинировать в любом порядке
Decorator vs Inheritance
| Аспект | Наследование | Decorator |
|---|---|---|
| Динамичность | Статичная | Динамичная (runtime) |
| Гибкость | Жёсткая иерархия | Легко комбинировать |
| Классов нужно | 2^n (комбинаторный взрыв) | n |
| Отношение | Is-A (есть связь) | Has-A (содержит) |
| Порядок | Фиксирован | Можно менять |
Вывод
Decorator паттерн позволяет:
- Добавлять новую функциональность к существующим классам
- Избежать создания множества подклассов
- Применять функциональность во время выполнения
- Комбинировать несколько декораторов
Это мощная альтернатива наследованию для расширения функциональности!