Страницы

Поиск по вопросам

вторник, 6 ноября 2018 г.

В чём отличия и сходства паттернов Adapter, Decorator, Wrapper и Proxy?

Здравствуйте. Разбираюсь понемного с паттернами проектирования, и не могу понять разницу в данных паттернах. В некоторых местах их считают синонимами. Отличия адаптера и декоратора я вроде бы нашёл (как я понял первый реализует интерфейс отличный, от интерфейса оборачиваемого объекта; а второй реализует тот же интерфейс, что и оборачиваемый объект). Но вот чем отличается адаптер от раппера (обёртки) найти не могу. Также не понятно, чем прокси отличается от декоратора. PS Желательны примеры кода, чтобы сразу увидеть отличия и сходства.


Ответ

Сперва маленькое уточнение: Wrapper -- это синоним декоратора. Т.о. речь в вопросе на самом деле идет о трех шаблонах: декоратор, адаптер и заместитель.

Все эти шаблоны схожи тем, что создают некоторую "обертку" вокруг класса. Так что ваши слова во многом справедливы:
ощущение, что это буквально один нож, которым кто-то режет хлеб, а кто-то строгает дерево, а кто-то - ещё как-то применяет его
Однако различаются они тем, какой интерфейс предоставляют и что делают с функциональностью оригинального класса (читай, внешний вид и предназначение ножа).
Заместитель (proxy) оборачивает некоторый класс и предоставляет такой же интерфейс. Цель -- "притвориться" оригинальным классом и скрыть от клиента детали. Типичные примеры использования -- ленивая инициализация оборачиваемого класса или оборачивание вызовов стороннего сервиса.
Декоратор также оборачивает некоторый класс и предоставляет такой же или расширенный интерфейс. Иногда декоратор называют "умным заместителем" (smart proxy). Т.е. декоратор может притворяться оригинальным классом и при этом расширять его функциональность. Пример: у вас есть заместитель, который прячет вызовы к стороннему сервису. Можно создать декоратор, который будет оборачивать и кэшировать результаты вызовов. Другой пример: нужно расширить функциональность оригинального класса, но он закрыт для наследования. Создается декоратор, который расширяет интерфейс оригинального класса.
Адаптер также оборачивает некоторый класс, но при этом предоставляет другой интерфейс. Т.е. используется в случаях, когда есть класс с нужными данными и поведением, но с неподходящим интерфейсом.
Итого:
--------------------------------------------------------------------------- | Шаблон | Что делает с интерфейсом | Что делает с функциональностью | --------------------------------------------------------------------------- | Заместитель | Не изменяет | Не изменяет | --------------------------------------------------------------------------- | Декоратор | Не изменяет/расширяет | Расширяет | --------------------------------------------------------------------------- | Адаптер | Изменяет | Не изменяет | ---------------------------------------------------------------------------

Что касается того, как они выглядят на уровне кода. Реализации, само собой, могут варьироваться, поэтому чтобы определить, что есть что, пользуйтесь следующими шагами:
Определите оригинальный объект/класс. Посмотрите, какой интерфейс предоставляет обертка. Посмотрите, какую функциональность предоставляет обертка.

Комментариев нет:

Отправить комментарий