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

Что такое паттерн Decorator?

2.0 Middle🔥 221 комментариев
#SOLID и паттерны проектирования

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

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

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

Паттерн Decorator

Decorator (Декоратор) — это структурный паттерн проектирования, который позволяет динамически добавлять новые обязанности объектам, оборачивая их в специальные обёртки. Это альтернатива наследованию, которая позволяет избежать создания множества подклассов для комбинирования функциональности.

Основная идея

Вместо создания новых классов через наследование, мы оборачиваем исходный объект в объект-декоратор, который реализует тот же интерфейс, но добавляет новую функциональность. Это делается во время выполнения программы, без изменения кода клиента.

Проблема, которую решает Decorator

Представьте, что нужно добавить различные расширения к классу (логирование, кэширование, сжатие и т.д.):

// Плохо: взрывное количество комбинаций
class DataStream { }
class LoggingDataStream extends DataStream { }
class CachingDataStream extends DataStream { }
class LoggingCachingDataStream extends DataStream { }
class CompressingLoggingCachingDataStream extends DataStream { }
// ... и так далее

Правильное решение с Decorator

1. Базовый интерфейс:

public interface DataStream {
    String read();
    void write(String data);
}

2. Конкретная реализация:

public class FileDataStream implements DataStream {
    @Override
    public String read() {
        return "Data from file";
    }
    
    @Override
    public void write(String data) {
        System.out.println("Writing to file: " + data);
    }
}

3. Абстрактный декоратор:

public abstract class DataStreamDecorator implements DataStream {
    protected DataStream wrappedStream;
    
    public DataStreamDecorator(DataStream stream) {
        this.wrappedStream = stream;
    }
    
    @Override
    public String read() {
        return wrappedStream.read();
    }
    
    @Override
    public void write(String data) {
        wrappedStream.write(data);
    }
}

4. Конкретные декораторы:

// Логирование
public class LoggingDecorator extends DataStreamDecorator {
    public LoggingDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        System.out.println("[LOG] Reading data");
        return wrappedStream.read();
    }
    
    @Override
    public void write(String data) {
        System.out.println("[LOG] Writing: " + data);
        wrappedStream.write(data);
    }
}

// Кэширование
public class CachingDecorator extends DataStreamDecorator {
    private String cache;
    
    public CachingDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        if (cache == null) {
            cache = wrappedStream.read();
        }
        return cache;
    }
    
    @Override
    public void write(String data) {
        cache = null;
        wrappedStream.write(data);
    }
}

// Сжатие
public class CompressionDecorator extends DataStreamDecorator {
    public CompressionDecorator(DataStream stream) {
        super(stream);
    }
    
    @Override
    public String read() {
        String data = wrappedStream.read();
        return decompress(data);
    }
    
    @Override
    public void write(String data) {
        String compressed = compress(data);
        wrappedStream.write(compressed);
    }
    
    private String compress(String data) {
        return "[COMPRESSED]" + data;
    }
    
    private String decompress(String data) {
        return data.replace("[COMPRESSED]", "");
    }
}

5. Использование:

// Создаём базовый поток
DataStream stream = new FileDataStream();

// Добавляем логирование
stream = new LoggingDecorator(stream);

// Добавляем кэширование
stream = new CachingDecorator(stream);

// Добавляем сжатие
stream = new CompressionDecorator(stream);

// Используем как обычный объект
String data = stream.read();
stream.write("Hello, World!");

Реальные примеры в Java

Потоки ввода-вывода:

InputStream input = new FileInputStream("file.txt");
input = new BufferedInputStream(input);  // Буферизация
input = new DataInputStream(input);      // Дополнительная функциональность

Collections.unmodifiable:

List<String> list = new ArrayList<>();
List<String> unmodifiable = Collections.unmodifiableList(list);
// unmodifiable — это декоратор, который оборачивает list

Преимущества и недостатки

Преимущества:

  • Гибкость: добавляем функциональность без изменения исходного кода
  • Комбинируемость: легко комбинировать несколько декораторов
  • Соответствие принципу Open/Closed: открыт для расширения, закрыт для модификации

Недостатки:

  • Может привести к большому количеству мелких классов
  • Порядок декораторов иногда имеет значение
  • Сложнее отладить, чем обычное наследование

Decorator — мощный паттерн для добавления динамической функциональности без нарушения принципов SOLID.