Ответ
Декоратор (Decorator) — это структурный паттерн, который позволяет динамически добавлять объектам новую функциональность, оборачивая их в объекты-«обёртки». Это гибкая альтернатива порождению подклассов для расширения поведения.
Зачем он нужен? Когда наследование неудобно или невозможно (например, класс final), или когда нужно добавлять обязанности объекту гибко и комбинировать их в разных порядках.
Пример на Java (кофе с добавками):
// 1. Базовый компонент
interface Coffee {
double getCost();
String getDescription();
}
// 2. Конкретный компонент
class SimpleCoffee implements Coffee {
@Override
public double getCost() { return 1.0; }
@Override
public String getDescription() { return "Simple coffee"; }
}
// 3. Базовый декоратор (абстрактный)
abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
// Делегирование вызовов обернутому объекту
@Override
public double getCost() { return decoratedCoffee.getCost(); }
@Override
public String getDescription() { return decoratedCoffee.getDescription(); }
}
// 4. Конкретные декораторы
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
@Override
public double getCost() {
return super.getCost() + 0.5; // Добавляем стоимость молока
}
@Override
public String getDescription() {
return super.getDescription() + ", milk";
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) { super(coffee); }
@Override
public double getCost() { return super.getCost() + 0.2; }
@Override
public String getDescription() { return super.getDescription() + ", sugar"; }
}
// 5. Использование
public class Main {
public static void main(String[] args) {
Coffee myCoffee = new SimpleCoffee();
System.out.println(myCoffee.getDescription() + " $" + myCoffee.getCost());
// Simple coffee $1.0
myCoffee = new MilkDecorator(myCoffee); // Декорируем молоком
myCoffee = new SugarDecorator(myCoffee); // Затем сахаром
System.out.println(myCoffee.getDescription() + " $" + myCoffee.getCost());
// Simple coffee, milk, sugar $1.7
}
}
Ключевые преимущества:
- Гибкость превыше наследования. Можно добавлять новые обязанности, не создавая иерархии подклассов.
- Динамическое добавление и удаление. Обёртки можно добавлять и комбинировать во время выполнения.
- Соблюдение принципа открытости/закрытости.
Классический пример в Java API: потоки ввода-вывода (java.io). Например, BufferedInputStream — это декоратор для FileInputStream, добавляющий буферизацию.
InputStream is = new BufferedInputStream(new FileInputStream("file.txt")); Ответ 18+ 🔞
О, слушай, а вот есть такая штука — Декоратор. Это, блядь, паттерн такой, структурный. Суть в чём: ты можешь на ходу, динамически, навешивать на объект новые пиздюлины, оборачивая его в специальные объекты-обёртки. Это типа как альтернатива наследованию, когда от класса плодить подклассы — это пиздец какой геморрой.
Нахуя это надо? Ну, например, когда наследование не катит — класс final, или когда тебе надо комбинировать фичи в разном порядке, и чтоб гибко, блядь.
Смотри, пример на Java (про кофе, классика же):
// 1. Базовый компонент — что угодно, что можно декорировать
interface Coffee {
double getCost();
String getDescription();
}
// 2. Конкретный компонент — просто кофе, голый
class SimpleCoffee implements Coffee {
@Override
public double getCost() { return 1.0; }
@Override
public String getDescription() { return "Simple coffee"; }
}
// 3. Базовый декоратор (абстрактный) — он и есть та самая обёртка
abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee; // Обёрнутый объект, его не трогаем
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
// Делегируем вызовы обёрнутому объекту по умолчанию
@Override
public double getCost() { return decoratedCoffee.getCost(); }
@Override
public String getDescription() { return decoratedCoffee.getDescription(); }
}
// 4. Конкретные декораторы — вот они, наши пиздюлины
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) { super(coffee); }
@Override
public double getCost() {
return super.getCost() + 0.5; // Накинули полтинник за молоко
}
@Override
public String getDescription() {
return super.getDescription() + ", milk";
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) { super(coffee); }
@Override
public double getCost() { return super.getCost() + 0.2; }
@Override
public String getDescription() { return super.getDescription() + ", sugar"; }
}
// 5. Использование — вот где магия, ёпта!
public class Main {
public static void main(String[] args) {
Coffee myCoffee = new SimpleCoffee();
System.out.println(myCoffee.getDescription() + " $" + myCoffee.getCost());
// Выведет: Simple coffee $1.0
// А теперь начинаем обёртывать, как душе угодно
myCoffee = new MilkDecorator(myCoffee); // Завернули в молоко
myCoffee = new SugarDecorator(myCoffee); // А потом ещё и в сахар
System.out.println(myCoffee.getDescription() + " $" + myCoffee.getCost());
// Выведет: Simple coffee, milk, sugar $1.7
}
}
Чем это, блядь, круто?
- Гибкость, а не наследование. Не надо плодить классы
CoffeeWithMilkAndSugar,CoffeeWithDoubleSugarAndNoMilk— ёб твою мать, с ума сойти можно. Просто оборачивай что надо. - Динамически, на лету. Можешь добавлять и снимать обёртки прямо во время выполнения. Хочешь — с сахаром, надоело — без.
- Принцип открытости/закрытости в действии. Классы закрыты для модификации, но открыты для расширения через эти самые декораторы.
Где это в жизни, блядь, видел? Да вон же, в Java IO! Это ж сплошные декораторы.
InputStream is = new BufferedInputStream(new FileInputStream("file.txt"));
BufferedInputStream — это декоратор для FileInputStream, который добавляет буферизацию. Без него читать файл — это как через соломинку воду пить, овердохуища времени уйдёт.