Что такое декоратор в Java?

Ответ

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

Пример:

interface Coffee {
    double getCost();
    String getDescription();
}

class SimpleCoffee implements Coffee {
    public double getCost() { return 2.0; }
    public String getDescription() { return "Simple Coffee"; }
}

class MilkDecorator implements Coffee {
    private Coffee coffee;
    public MilkDecorator(Coffee coffee) { this.coffee = coffee; }
    public double getCost() { return coffee.getCost() + 0.5; }
    public String getDescription() { return coffee.getDescription() + ", Milk"; }
}

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

Coffee coffee = new MilkDecorator(new SimpleCoffee());
System.out.println(coffee.getDescription()); // "Simple Coffee, Milk"
System.out.println(coffee.getCost()); // 2.5

Декоратор сохраняет интерфейс исходного объекта и расширяет его поведение без наследования.

Ответ 18+ 🔞

А, декоратор! Ну это ж классика, ебать мои старые костыли. Представь себе ситуацию: есть у тебя объект, простой как три копейки. И вдруг тебе надо, чтобы он делал то же самое, но ещё и с перламутровыми пуговицами. Наследоваться? Да ну нахуй, это же жёсткая сцепка, потом от этого класса-урода все поломается.

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

Смотри на примере кофе, тут всё понятно становится, ёпта.

interface Coffee {
    double getCost();
    String getDescription();
}

class SimpleCoffee implements Coffee {
    public double getCost() { return 2.0; }
    public String getDescription() { return "Simple Coffee"; }
}

class MilkDecorator implements Coffee {
    private Coffee coffee;
    public MilkDecorator(Coffee coffee) { this.coffee = coffee; }
    public double getCost() { return coffee.getCost() + 0.5; }
    public String getDescription() { return coffee.getDescription() + ", Milk"; }
}

Видишь, MilkDecorator? Он сам реализует Coffee, но в конструктор принимает тоже какой-то Coffee. Он не наследует SimpleCoffee, он его оборачивает. Внутри себя он вызывает методы того кофе, что ему передали, и добавляет сверху своё: цену молока и строчку в описание.

А теперь смотри, как это круто работает:

Coffee coffee = new MilkDecorator(new SimpleCoffee());
System.out.println(coffee.getDescription()); // "Simple Coffee, Milk"
System.out.println(coffee.getCost()); // 2.5

Создал простой кофе, обернул в декоратор молока — и получил новый объект. Хочешь ещё сироп? Без проблем! Оберни результат ещё в SyrupDecorator!

Coffee coffee = new SyrupDecorator(new MilkDecorator(new SimpleCoffee()));

Получится матрёшка, ёперный театр! Каждый декоратор добавляет свой функционал, и ты в любой момент можешь скомбинировать их как угодно, не создавая овердохуища классов вроде SimpleCoffeeWithMilkAndSyrupAndCinnamonAndWhippedCream.

Вот и весь фокус. Вместо того чтобы плодить наследников на каждый чих, ты создаёшь гибкие обёртки. Красота, да и только. Главное — не переборщить, а то наслоишь этих декораторов, что в итоге хуй с горы разберёшь, что там внутри и в каком порядке выполняется.