В чем разница между паттернами адаптер и декоратор?
Что проверяют
Понимаете ли вы, что оба паттерна оборачивают объект, но с разными целями. Структурно они похожи, и различие именно в намерении.
Как отвечать
Адаптер меняет интерфейс, не трогая поведение. Есть класс, который делает нужное, но зовётся не так, как ожидает ваш код: адаптер переводит вызовы. Классика это подключение чужой библиотеки или старого кода к новому контракту.
Декоратор сохраняет интерфейс и добавляет поведение. Обёртка реализует тот же интерфейс, что и объект внутри, поэтому её можно подставить всюду, где ожидался исходный объект, и при этом навесить кеширование, журналирование, повторные попытки, проверку прав.
Разница в одной фразе: адаптер про «не подходит разъём», декоратор про «работает, но нужно ещё кое-что по дороге».
// Декоратор: тот же интерфейс, добавлен кеш
class CachedJobRepository implements JobRepository {
private final JobRepository delegate;
public Job find(String id) { return cache.computeIfAbsent(id, delegate::find); }
}Что стоит добавить:
- декораторы складываются: кеш поверх повторных попыток поверх журналирования, и порядок обёрток меняет поведение;
- адаптер обычно один и на этом заканчивается;
- в стандартной библиотеке декораторы это потоки ввода-вывода (
BufferedInputStreamповерхFileInputStream) иCollections.unmodifiableList, а адаптеры этоArrays.asListи обёртки над старым API; - рядом стоят похожие паттерны: заместитель (тот же интерфейс, но управляет доступом и жизненным циклом) и фасад (упрощает сложную подсистему одним интерфейсом).
Где спотыкаются
Называют декоратором любую обёртку, даже если интерфейс изменился.
Не могут объяснить, зачем декоратору реализовывать тот же интерфейс: именно это делает его прозрачным для вызывающего кода.
Путают с заместителем: у обоих один интерфейс, но декоратор расширяет поведение, а заместитель контролирует доступ.