Что такое паттерн Декоратор и приведи пример его использования?

«Что такое паттерн Декоратор и приведи пример его использования?» — вопрос из категории Паттерны, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Паттерн Декоратор (Decorator) динамически добавляет объекту новые обязанности, предоставляя гибкую альтернативу наследованию для расширения функциональности.

Пример: Добавление дополнительного поведения (сжатия, шифрования) к базовому потоку данных.

// 1. Базовый компонент
interface DataSource {
    void writeData(String data);
    String readData();
}

// 2. Конкретная реализация компонента
class FileDataSource implements DataSource {
    private String filename;
    // ... реализация работы с файлом
    public void writeData(String data) { /* запись в файл */ }
    public String readData() { /* чтение из файла */ return ""; }
}

// 3. Базовый декоратор
abstract class DataSourceDecorator implements DataSource {
    protected DataSource wrappee;

    public DataSourceDecorator(DataSource source) {
        this.wrappee = source;
    }
}

// 4. Конкретные декораторы
class EncryptionDecorator extends DataSourceDecorator {
    public EncryptionDecorator(DataSource source) { super(source); }

    @Override
    public void writeData(String data) {
        String encryptedData = encrypt(data); // Логика шифрования
        wrappee.writeData(encryptedData);
    }

    @Override
    public String readData() {
        String data = wrappee.readData();
        return decrypt(data); // Логика дешифрования
    }
    // ... методы encrypt() и decrypt()
}

class CompressionDecorator extends DataSourceDecorator {
    // ... аналогично, добавляет логику сжатия/распаковки
}

// 5. Использование: комбинирование декораторов
public class Client {
    public static void main(String[] args) {
        DataSource source = new FileDataSource("data.txt");
        // Обертывание: сначала сжатие, затем шифрование
        source = new CompressionDecorator(source);
        source = new EncryptionDecorator(source);

        source.writeData("Secret data"); // Данные будут сжаты, зашифрованы и записаны
    }
}

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