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

Ответ

Паттерн Декоратор (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"); // Данные будут сжаты, зашифрованы и записаны
    }
}

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

Ответ 18+ 🔞

Да ты посмотри, какой гибкий пиздец! Паттерн Декоратор — это как если бы ты взял обычный бутерброд и начал на него хуячить всё, что в холодильнике нашёл: колбасу, сыр, икру, блядь, майонез, огурчик. И каждый слой — это новый декоратор, а сам хлеб — это базовый компонент, ёпта.

Смотри, как это работает, на примере записи данных. Вот у тебя есть просто файл, туда можно писать и читать. Скукота, блядь.

interface DataSource {
    void writeData(String data);
    String readData();
}

Конкретная реализация — это просто файловая система, всё как у людей.

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

А теперь начинается магия, ебать мои старые костыли! Мы не хотим лезть в этот класс и пихать туда всё подряд. Вместо этого мы делаем обёртку — базовый декоратор.

abstract class DataSourceDecorator implements DataSource {
    protected DataSource wrappee; // Вот эта сука, которую мы оборачиваем

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

И теперь мы можем накручивать функциональность, как блядские блины на Масленицу. Хочешь шифрование? Пожалуйста!

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 {
    // ... аналогично, добавляет логику сжатия/распаковки
}

А теперь смотри, как это всё собирается в коде клиента. Это просто песня, блядь!

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");
    }
}

В чём, сука, кайф? А в том, что ты можешь комбинировать эти обёртки в любом порядке, да хоть на ходу менять! Не нужно городить овердохуища подклассов типа EncryptedAndCompressedFileDataSource или CompressedButNotEncryptedFileDataSource. Всё, блядь, модульно и переиспользуемо. Добавил новое поведение — написал один новый декоратор и оборачивай им что угодно. Красота, ёпта!