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

«Что такое паттерн Декоратор?» — вопрос из категории ООП, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять новое поведение объектам, оборачивая их в объекты-декораторы, не изменяя их исходный код.

Ключевые принципы:

  • Композиция вместо наследования: Поведение добавляется через агрегацию, что уменьшает связность по сравнению с созданием глубоких иерархий классов.
  • Принцип открытости/закрытости (Open/Closed): Классы открыты для расширения (через декораторы), но закрыты для модификации.
  • Прозрачность: Декоратор имеет тот же интерфейс, что и оборачиваемый компонент, поэтому клиентский код работает с ними одинаково.

Пример реализации на Java:

// 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 encryptedData = wrappee.readData();
        return decrypt(encryptedData); // Логика дешифрования
    }
    private String encrypt(String data) { /* ... */ return data; }
    private String decrypt(String data) { /* ... */ return data; }
}

// 5. Использование
public class Main {
    public static void main(String[] args) {
        DataSource source = new FileDataSource("data.txt");
        // Динамически добавляем шифрование
        DataSource encryptedSource = new EncryptionDecorator(source);
        encryptedSource.writeData("Секретные данные");
    }
}

Типичное применение: Добавление логирования, кеширования, сжатия, шифрования, валидации или контроля доступа к операциям ввода-вывода, веб-запросам или бизнес-сервисам.