Загрузка...
Загрузка...
Декоратор (Decorator) — это структурный паттерн проектирования, который позволяет динамически добавлять объекту новые обязанности, оборачивая его в объекты-«декораторы». При этом исходный объект не изменяется, а дополнительная логика «подмешивается» извне.
Зачем нужен Декоратор:
Паттерн «Декоратор» позволяет гибко расширять функциональность объектов, не изменяя их код. Это особенно удобно, если нельзя (или нежелательно) использовать наследование.
Когда нужно добавлять новые возможности объектам «на лету» без создания множества подклассов.
Когда невозможно или нежелательно модифицировать класс напрямую (например, классы из сторонней библиотеки).
Когда несколько видов функционала надо сочетать по-разному. Декораторы позволяют комбинировать фичи, не создавая взрывного числа подклассов.
Таким образом, декораторы могут оборачивать друг друга, создавая цепочку объектов, — каждый добавляет свои особенности.
// 1. Базовый интерфейс для компонентов
interface DataSource {
writeData(data: string): void;
readData(): string;
}
// 2. Конкретный класс, реализующий интерфейс
class FileDataSource implements DataSource {
private filename: string;
private buffer: string;
constructor(filename: string) {
this.filename = filename;
this.buffer = "";
}
writeData(data: string): void {
// Логика записи данных в файл
this.buffer = data;
console.log(`Data "${data}" written to file: ${this.filename}`);
}
readData(): string {
// Логика чтения данных из файла
console.log(`Reading data from file: ${this.filename}`);
return this.buffer;
}
}
// 3. Общий класс-декоратор
class DataSourceDecorator implements DataSource {
protected wrappee: DataSource;
constructor(source: DataSource) {
this.wrappee = source;
}
writeData(data: string): void {
this.wrappee.writeData(data);
}
readData(): string {
return this.wrappee.readData();
}
}
// 4. Конкретные декораторы
class EncryptionDecorator extends DataSourceDecorator {
writeData(data: string): void {
const encrypted = btoa(data); // простенькая "шифрация" Base64
console.log("Encrypting data...");
super.writeData(encrypted);
}
readData(): string {
const data = super.readData();
console.log("Decrypting data...");
return atob(data);
}
}
class CompressionDecorator extends DataSourceDecorator {
writeData(data: string): void {
console.log("Compressing data...");
const compressed = `COMPRESSED(${data})`;
super.writeData(compressed);
}
readData(): string {
const data = super.readData();
console.log("Decompressing data...");
return data.replace(/^COMPRESSED\(|\)$/g, "");
}
}
// 5. Клиентский код
function clientCode() {
const file = new FileDataSource("data.txt");
// Оборачиваем файл декораторами
const encryption = new EncryptionDecorator(file);
const compression = new CompressionDecorator(encryption);
// Запись
compression.writeData("Hello, Decorator!");
// Чтение
console.log("Final data:", compression.readData());
}
clientCode();
Важно:
Если вы используете слишком много декораторов, это может усложнить логику следования операций. Оценивайте, насколько действительно нужна динамика и гибкость, прежде чем вводить паттерн «Декоратор».
Подробнее про Декоратор можно почитать здесь.