Ответ
Декоратор — это структурный паттерн проектирования, который позволяет динамически добавлять новое поведение объектам, оборачивая их в объекты-декораторы, не изменяя их исходный код.
Ключевые принципы:
- Композиция вместо наследования: Поведение добавляется через агрегацию, что уменьшает связность по сравнению с созданием глубоких иерархий классов.
- Принцип открытости/закрытости (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("Секретные данные");
}
}
Типичное применение: Добавление логирования, кеширования, сжатия, шифрования, валидации или контроля доступа к операциям ввода-вывода, веб-запросам или бизнес-сервисам.
Ответ 18+ 🔞
Давай я тебе на пальцах объясню, что за зверь такой — декоратор. Представь, у тебя есть голая, голая функция, как будто ты сам из душа вышел. Она умеет писать и читать данные, ну, допустим, в файл. Всё, больше нихуя. А потом тебе начальник приходит и говорит: «А сделай-ка шифрование, а то данные секретные». Ты, конечно, мог бы наследоваться от этого класса и накрутить кучу наследников: EncryptedFileDataSource, CompressedFileDataSource, а потом ещё и EncryptedAndCompressedFileDataSource... Ёперный театр, это же пиздопроебибна получается, классов будет овердохуища, и каждый новый запрос — это новая иерархия, голова пухнет.
Вот тут-то декоратор и выручает, ядрёна вошь! Суть проще пареной репы. Мы не лезем в кишки исходного класса, а просто берём и оборачиваем его, как капустный лист голубцы, в другой объект. Этот объект-обёртка имеет тот же самый интерфейс, что и оригинал, но внутри он делает своё дело (например, шифрует), а потом передаёт вызов дальше, тому, кого он обернул.
Смотри на примере кода. Вот наш скромный работяга, который пишет в файл:
class FileDataSource implements DataSource {
// ... тут он просто пишет и читает, как честный труженик
}
А теперь появляется наш декоратор — хитрая жопа, которая хочет добавить своё поведение. Он тоже реализует DataSource, но в конструкторе принимает другой DataSource, который он будет оборачивать.
class EncryptionDecorator extends DataSourceDecorator {
@Override
public void writeData(String data) {
String encryptedData = encrypt(data); // 1. Сначала шифруем
wrappee.writeData(encryptedData); // 2. Потом отдаём обёрнутому объекту
}
}
И вся магия в том, что ты можешь оборачивать объекты в сколько угодно обёрток, и они будут выполняться по цепочке, как матрёшки. Хочешь сжать и зашифровать? Без проблем!
DataSource source = new FileDataSource("data.txt");
source = new CompressionDecorator(source); // Сначала сожмём
source = new EncryptionDecorator(source); // Потом зашифруем то, что сжали
source.writeData("Секретные данные"); // И всё это пройдёт по цепочке
Получается гибко, как хуй в пальто: ты динамически, на лету, собираешь нужную функциональность. Никакого монструозного наследования, всё через композицию. Принцип «открыт для расширения, закрыт для изменения» в действии, ёпта. Используют эту штуку везде, где нужно добавить какую-то дополнительную логику — логирование, кеширование, проверку прав. В общем, паттерн — просто огонь, когда нужно накрутить поведение без головной боли.
Видео-ответы
▶
▶
▶
▶
▶