Decorator — это структурный паттерн, позволяющий на лету расширять поведение объекта, не изменяя его класс. Исходный объект помещается внутрь другого — декоратора, — который перехватывает вызовы и дополняет их нужной функциональностью.
Принцип тот же, что у матрёшки: каждый новый слой добавляет что-то своё.
▪️ Пример:
Сервис обработки данных: базовая загрузка, поверх — логирование, поверх — кэширование. Каждый слой добавляется независимо.
// Базовый интерфейс
interface DataService {
String getData(String key);
}
// Базовая реализация
class DatabaseService implements DataService {
public String getData(String key) {
return "data_from_db_" + key; // запрос в БД
}
}
// Абстрактный декоратор
abstract class DataServiceDecorator implements DataService {
protected final DataService delegate;
public DataServiceDecorator(DataService delegate) {
this.delegate = delegate;
}
}
// Декоратор логирования
class LoggingDecorator extends DataServiceDecorator {
public LoggingDecorator(DataService delegate) {
super(delegate);
}
public String getData(String key) {
System.out.println("LOG: запрос ключа " + key);
String result = delegate.getData(key);
System.out.println("LOG: получен результат");
return result;
}
}
// Декоратор кэширования
class CachingDecorator extends DataServiceDecorator {
private final Map<String, String> cache = new HashMap<>();
public CachingDecorator(DataService delegate) {
super(delegate);
}
public String getData(String key) {
return cache.computeIfAbsent(key, delegate::getData);
}
}
// Использование — собираем как конструктор
DataService service = new CachingDecorator(
new LoggingDecorator(
new DatabaseService()
)
);
service.getData("user:42"); // лог + БД + кэш
service.getData("user:42"); // кэш (без лога и БД)
▪️ Когда использовать
— Нужно добавить поведение объекту без наследования
— Комбинации поведений непредсказуемы (логирование + кэш + метрики в любом порядке)
— Классический пример в JDK: InputStream → BufferedInputStream → GZIPInputStream
▪️ Decorator vs наследование
— Наследование: статическое, одно на класс
— Decorator: динамическое, можно комбинировать
▪️ Минус
Много мелких классов; отладка стека из нескольких обёрток может быть неудобной.
🐸 Библиотека собеса по Java
#patterns