Перейти к основному содержимому

Паттерн "Декоратор" (Decorator) в Java — расширение поведения без наследования

Разработчику Архитектору

Обзор — в структурных паттернах. Здесь — практический Decorator на Java через слой логирования и слой кеша.

Загрузка редактора схем…

Задача паттерна

Decorator добавляет поведение объекту в runtime без изменения его класса.

Идея простая: объект оборачивается в другой объект с тем же интерфейсом. Каждый слой может добавить логику до/после делегирования.


Пример — сервис данных

import java.util.HashMap;
import java.util.Map;

interface DataService {
String getData(String key);
}

class DatabaseService implements DataService {
@Override
public String getData(String key) {
return "data_from_db_" + key;
}
}

abstract class DataServiceDecorator implements DataService {
protected final DataService delegate;

protected DataServiceDecorator(DataService delegate) {
this.delegate = delegate;
}
}

class LoggingDecorator extends DataServiceDecorator {
LoggingDecorator(DataService delegate) {
super(delegate);
}

@Override
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<>();

CachingDecorator(DataService delegate) {
super(delegate);
}

@Override
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"); // кеш

Когда использовать

СигналПочему Decorator
Комбинации поведения заранее неизвестныСлои добавляются и переставляются
Нежелательно раздувать иерархию наследованияИзбегаем ServiceWithLogAndCacheAndMetrics
Нужно расширять в runtimeНовая обертка подключается конфигурацией

В JDK тот же принцип в I/O: InputStream -> BufferedInputStream -> GZIPInputStream.


Decorator и Proxy

DecoratorProxy
НазначениеРасширение поведенияКонтроль доступа и жизненного цикла
ФокусДополнительные возможностиПроверка прав, lazy, удаленный вызов

Практика Proxy на Java — 128.


Риски

Много мелких классов и сложный стек оберток в отладке. Держите прозрачные имена (CachingDecorator, MetricsDecorator) и фиксируйте порядок в конфигурации.


См. также

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").