← Назад к вопросам

Как работает паттерн проектирования Decorator?

1.3 Junior🔥 131 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Паттерн 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 паттерн позволяет:

  • Добавлять новую функциональность к существующим классам
  • Избежать создания множества подклассов
  • Применять функциональность во время выполнения
  • Комбинировать несколько декораторов

Это мощная альтернатива наследованию для расширения функциональности!