Adapter (Wrapper). Шаблон проектирования.

27. December 2009

Гипотетический случай из жизни:
    Представьте, что вы сантехник и пришли поставить новый кран клиенту. Клиент вас встречает, чаем угощает, рассказывает "так мол и так, кран потек :-'( Надо новый ставить, стрый совсем плохой стал." Дает в руки вам смеситель, который вчера купил и провожает в ванную. Вы достаете разводной ключ и лихо откручиваете старый смеситель и уже собираетесь привернуть новый, как замечаете, что у наих трубки подвода воды разных диаметров. И тут вы могли бы сказать клиенту, что он не то купил и уйти, но чай выпит, в карманах пусто, а заработать хочется. Что делать?! Хорошо с собой есть такая классная штучка как муфта! С одной стороны она отлично наварачивается на трубки которые подводят воду, с другой замечательно вкручивается в новый смеситель, да и сама размером длинной пару сантиметров не более. Работа сделана, деньги в кармане, клиент доволен, проблема побеждена. Молодцы? А то!
 
Случай из практики разработки программ:
    А теперь вернемся обратно к программированию, а именно к шаблонам проектирования. Скажите, у вас случалась ситуация, когда несколько человек проектирую одну систему, предварительно разделив ее на компоненты, а когда настает время соединить все вместе, то оно не соединяется. Ну не стыкуется один код с другим и все! Методы делают то, что нужно, а интерфейсы разные. Количество параметров не совпадает или нельзя просто вызвать метод, нужно еще предварительно настроить объект, который содержит метод.  Проблема... :-( И что теперь делать? Деньги на разработку компонентов потрачены, менять интерфейсы стыковых классов нельзя(это, вроде как, основное ограничение), потому что они завязаны еще много где и придется перелопачиваться и там. А изменения там потребуют изменений еще где нибудь... Затратно это и рисковано!
 
    Или так. Представьте, что нашли нужную библиотеку компонентов, а интегрировать со своим кодом не можете, интерфейсы разные. Изменить интерфейсы библиотеки тоже не можете, исходников нет и вообще по лицензии запрещено, что либо менять)
Основная проблема в том, что нужно использовать компоненты интерфейс которых не совпадает с интерфейсом, которого вы ожидаете в использовании.
 
    Ситуация напоминает ситуацию со смесителем, да? Тут решение такое же, нам нужен специальный переходник - Адаптер. Этот Адаптер приведет интерфейс используемого класса к интерфейсу, который ожидает класс использующий его(клиент). Проблема будет решена, интеграция компонентов пройдет успешно и довольные разработчики наконец пойдут отмечать успех!
 
    Плюсы:

  •     инкапсуляция реализации внешних классов (компонентов, библиотек), система становится независимой от интерфейса внешних классов;
  •     переход на использование других внешних классов не требует переделки самой системы, достаточно реализовать один класс Adapter.

    
    Шаблон Адаптер позволяет в процессе проектирования не принимать во внимание возможные различия в интерфейсах уже существующих классов. Если есть класс, обладающий требуемыми методами и свойствами (по крайней мере, концептуально), то при необходимости всегда можно воспользоваться шаблоном Адаптер для приведения его интерфейса к нужному виду.все что выделено. Взято из Wiki
     В отличии от шаблона Адаптер, шаблон Декоратор несет функции подключения дополнительных обязательств к объекту. И приведение одного интерфейса к другому это всего лишь побочный эффект.
     Разница между Фасадом и  Адаптером в том, что шаблон Фасад предназначен для упрощения интерфейса, тогда как шаблон Адаптер предназначен для приведения различных существующих интерфейсов к единому требуемому виду.

 
В диаграмме классов это будет выглядеть так.

 


Картинка взята с вики, а туда ее засунули, наверняка, из книжки GOF. Design Patterns

 
    Клиент ожидал, что класс который он будет использовать имеет интерфейс класса Target, а вышло так, что  ему доступен только интерфейс Adaptree. Функционально методы ожидаемый и тот, что есть делают все правильно. Входные данные и выходные соответствуют, проблема в том как данные передаются и как выводятся. Эти проблемы решает класс Adapter. Он является наследником класса Target, который предоставляет тот интерфейс, что нужен клиенту. И как наследник он переопределяет методы нужные клиенту, в которых обращается к классу Adaptree, который предоставляет текущую реализацию. Таким образом, класс Adapter полностью скрывает конвертацию передачи данных от одного класса к другому от класса клиента.



В будущем, если вернусь к этому шаблону,  напишу про:

 

  •     Разницу между адаптером объектов и адаптером классов.
  •     Три подхода реализации Адаптера с примерами кода

 

Architecture, Design Patterns , ,

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading