В программной инженерии , то шаблон адаптера является разработка программного обеспечения модель (также известная как обертки, альтернативное именование совместно с рисунком декоратора ) , что позволяет интерфейс существующего класса для использования в качестве другого интерфейса. [1] Он часто используется для того, чтобы существующие классы работали с другими без изменения их исходного кода .
Пример представляет собой адаптер , который преобразует интерфейс из объектной модели документа в качестве XML - документа в виде древовидной структуры , которые могут быть отображены.
Обзор
Шаблон проектирования адаптер [2] - один из двадцати трех хорошо известных шаблонов проектирования « Банда четырех», которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменение, тестирование и повторное использование.
Шаблон проектирования адаптера решает следующие проблемы: [3]
- Как можно повторно использовать класс, не имеющий интерфейса, который требуется клиенту?
- Как могут работать вместе классы с несовместимыми интерфейсами?
- Как можно предоставить альтернативный интерфейс для класса?
Часто (уже существующий) класс нельзя повторно использовать только потому, что его интерфейс не соответствует интерфейсу, который требуется клиентам.
В шаблоне проектирования адаптера описано, как решать такие проблемы:
- Определите отдельный
adapter
класс, который преобразует (несовместимый) интерфейс класса (adaptee
) в другой интерфейс (target
), который требуется клиентам. - Поработайте над тем,
adapter
чтобы работать (повторно использовать) классы, у которых нет необходимого интерфейса.
Ключевая идея в этом шаблоне - работать через отдельный adapter
, адаптирующий интерфейс (уже существующего) класса без его изменения.
Клиенты не знают, работают ли они с target
классом напрямую или через adapter
класс, у которого нет target
интерфейса.
См. Также диаграмму классов UML ниже.
Определение
Адаптер позволяет двум несовместимым интерфейсам работать вместе. Это реальное определение адаптера. Интерфейсы могут быть несовместимы, но внутренняя функциональность должна соответствовать потребностям. Шаблон проектирования адаптера позволяет несовместимым классам работать вместе, преобразовывая интерфейс одного класса в интерфейс, ожидаемый клиентами.
Применение
Адаптер можно использовать, когда оболочка должна учитывать определенный интерфейс и поддерживать полиморфное поведение. В качестве альтернативы декоратор позволяет добавлять или изменять поведение интерфейса во время выполнения, а фасад используется, когда требуется более простой или более простой интерфейс для базового объекта. [4]
Шаблон | Намерение |
---|---|
Адаптер или обертка | Преобразует один интерфейс в другой, чтобы он соответствовал ожиданиям клиента. |
Декоратор | Динамически добавляет ответственности к интерфейсу, упаковывая исходный код |
Делегация | Поддержка «композиции над наследованием» |
Фасад | Обеспечивает упрощенный интерфейс |
Состав
Диаграмма классов UML
На приведенной выше диаграмме классов UML класс , client
которому требуется target
интерфейс, не может повторно использовать adaptee
класс напрямую, потому что его интерфейс не соответствует target
интерфейсу. Вместо этого он client
работает через adapter
класс, реализующий target
интерфейс с точки зрения adaptee
:
object adapter
Способ реализуетtarget
интерфейс путем передачи кadaptee
объекту во время выполнения (adaptee.specificOperation()
).- В
class adapter
способ реализуетtarget
интерфейс путем наследования отadaptee
класса во время компиляции (specificOperation()
).
Шаблон адаптера объекта
В этом шаблоне адаптера адаптер содержит экземпляр класса, который он обертывает. В этой ситуации адаптер вызывает экземпляр обернутого объекта .
Шаблон адаптера класса
Этот шаблон адаптера использует несколько полиморфных интерфейсов, реализующих или наследующих как ожидаемый, так и уже существующий интерфейс. Обычно ожидаемый интерфейс создается как чистый интерфейсный класс, особенно в таких языках , как Java (до JDK 1.8), которые не поддерживают множественное наследование классов. [1]
Еще одна форма шаблона адаптера среды выполнения
Мотивация от решения во время компиляции
Желательно classA
предоставить classB
какие-то данные, допустим, какие-то String
данные. Решение времени компиляции:
classB . setStringData ( classA . getStringData ());
Однако предположим, что формат строковых данных должен быть изменен. Решение во время компиляции - использовать наследование:
открытый класс Format1ClassA расширяет ClassA { @Override public String getStringData () { return format ( toString ()); } }
и, возможно, создать правильно "форматирующий" объект во время выполнения с помощью фабричного шаблона .
Решение для адаптера времени выполнения
Решение с использованием «переходников» происходит следующим образом:
- Определите промежуточный интерфейс «поставщика» и напишите реализацию этого интерфейса поставщика, которая обертывает источник данных
ClassA
в этом примере и выводит данные в соответствующем формате:общедоступный интерфейс StringProvider { общедоступная строка getStringData (); }открытый класс ClassAFormat1 реализует StringProvider { частный ClassA classA = null ; общедоступный ClassAFormat1 ( окончательный ClassA a ) { classA = a ; } общедоступная строка getStringData () { формат возврата ( classA . getStringData ()); } private String format ( final String sourceValue ) { // Преобразование исходной строки в формат, // требуемый объектом, требующим возврата данных исходного объекта sourceValue . обрезать (); } }
- Напишите класс адаптера, который возвращает конкретную реализацию поставщика:
открытый класс ClassAFormat1Adapter расширяет адаптер { адаптация открытого объекта ( конечный объект и объект ) { возвращает новый ClassAFormat1 (( ClassA ) anObject ); } }
- Зарегистрируйте в
adapter
глобальном реестре, чтобыadapter
можно было искать во время выполнения:АдаптерФабрика . getInstance (). registerAdapter ( ClassA . класс , ClassAFormat1Adapter . класс , "формат1" );
- В коде, если вы хотите передать данные из
ClassA
вClassB
, напишите:Адаптер- адаптер = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . класс , StringProvider . класс , "format1" ); StringProvider provider = ( StringProvider ) адаптер . адаптироваться ( класс A ); Строка строка = поставщик . getStringData (); classB . setStringData ( строка );
или более кратко:
classB . setStringData ( (( StringProvider ) AdapterFactory . деЫпзЬапс () . getAdapterFromTo ( ClassA . класс , StringProvider . класс , "формат 1 " ) . адаптируется ( CLASSA )) . getStringData ());
- Преимущество можно увидеть в том, что если требуется передать данные во втором формате, найдите другой адаптер / поставщик:
Адаптер- адаптер = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . class , StringProvider . class , "format2" );
- И если желательно вывести данные
ClassA
, скажем, как данные изображения в :Class C
Адаптер- адаптер = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . class , ImageProvider . class , "format2" ); ImageProvider provider = ( ImageProvider ) адаптер . адаптироваться ( класс A ); classC . setImage ( поставщик . getImage ());
- Таким образом, использование адаптеров и поставщиков позволяет использовать несколько «мнение» от
ClassB
иClassC
IntoClassA
без необходимости изменять иерархию классов. В общем, он позволяет использовать механизм для произвольных потоков данных между объектами, который можно модифицировать для существующей иерархии объектов.
Реализация шаблона адаптера
При реализации шаблона адаптера для ясности можно применить имя класса к реализации поставщика; например ,. Он должен иметь метод конструктора с переменной адаптируемого класса в качестве параметра. Этот параметр будет передан члену экземпляра . Когда вызывается clientMethod, он будет иметь доступ к экземпляру адаптируемого объекта, который позволяет получить доступ к необходимым данным адаптируемого объекта и выполнять операции с этими данными, которые генерируют желаемый результат.[ClassName]To[Interface]Adapter
DAOToProviderAdapter
[ClassName]To[Interface]Adapter
Ява
интерфейс LightningPhone { void recharge (); void useLightning (); }интерфейс MicroUsbPhone { void recharge (); void useMicroUsb (); }класс Iphone реализует LightningPhone { частный логический соединитель ; @Override public void useLightning () { connector = true ; Система . из . println ( «Молния подключена» ); } @Override public void recharge () { if ( коннектор ) { System . из . println ( «Пополнение началось» ); Система . из . println ( «Пополнение баланса завершено» ); } else { System . из . println ( «Сначала подключите Lightning» ); } } }класс Android реализует MicroUsbPhone { частный логический коннектор ; @Override public void useMicroUsb () { connector = true ; Система . из . println ( «MicroUsb подключен» ); } @Override public void recharge () { if ( коннектор ) { System . из . println ( «Пополнение началось» ); Система . из . println ( «Пополнение баланса завершено» ); } else { System . из . println ( «Сначала подключите MicroUsb» ); } } } / * отображение целевого интерфейса при упаковке исходного объекта * / class LightningToMicroUsbAdapter реализует MicroUsbPhone { private final LightningPhone lightningPhone ; public LightningToMicroUsbAdapter ( LightningPhone lightningPhone ) { this . lightningPhone = lightningPhone ; } @Override public void useMicroUsb () { System . из . println ( «MicroUsb подключен» ); молнияТелефон . useLightning (); } @Override public void recharge () { lightningPhone . перезарядка (); } }открытый класс AdapterDemo { static void rechargeMicroUsbPhone ( MicroUsbPhone phone ) { phone . useMicroUsb (); телефон . перезарядка (); } static void rechargeLightningPhone ( телефон LightningPhone ) { phone . useLightning (); телефон . перезарядка (); } public static void main ( String [] args ) { Android android = new Android (); Iphone iPhone = новый Iphone (); Система . из . println ( «Зарядка андроида с помощью MicroUsb» ); rechargeMicroUsbPhone ( android ); Система . из . println ( «Зарядка iPhone с помощью молнии» ); rechargeLightningPhone ( iPhone ); Система . из . println ( «Зарядка iPhone с помощью MicroUsb» ); rechargeMicroUsbPhone ( новый LightningToMicroUsbAdapter ( iPhone )); } }
Выход
Зарядка андроида с помощью MicroUsbMicroUsb подключенПополнение началосьПерезарядка завершенаЗарядка iPhone с помощью LightningМолния подключенаПополнение началосьПерезарядка завершенаЗарядка iPhone с помощью MicroUsbMicroUsb подключенМолния подключенаПополнение началосьПерезарядка завершена
Python
«» « Шаблон Пример адаптера. „“» От аЬса импорт ABCMeta , abstractmethodNOT_IMPLEMENTED = "Вы должны реализовать это."RECHARGE = [ "Перезарядка началась." , "Перезарядка завершена". ]POWER_ADAPTERS = { "Android" : "MicroUSB" , "iPhone" : "Lightning" }CONNECTED = " {} подключено." CONNECT_FIRST = " Сначала подключите {} ."класс RechargeTemplate : __metaclass__ = ABCMeta @abstractmethod def recharge ( self ): поднять NotImplementedError ( NOT_IMPLEMENTED )class FormatIPhone ( RechargeTemplate ): @abstractmethod def use_lightning ( self ): поднять NotImplementedError ( NOT_IMPLEMENTED )class FormatAndroid ( RechargeTemplate ): @abstractmethod def use_micro_usb ( self ): поднять NotImplementedError ( NOT_IMPLEMENTED )класс IPhone ( FormatIPhone ): __name__ = "iPhone" def __init__ ( self ): себя . connector = False def use_lightning ( self ): себя . Connector = True print ( ПОДКЛЮЧЕН . формат ( АДАПТЕРЫ ПИТАНИЯ [ сам . __name__ ])) def recharge ( self ): если self . соединитель : для состояния в RECHARGE : print ( state ) else : print ( CONNECT_FIRST . format ( POWER_ADAPTERS [ self . __name__ ]))класс Android ( FormatAndroid ): __name__ = "Android" def __init__ ( self ): себя . connector = False def use_micro_usb ( сам ): себя . Connector = True print ( ПОДКЛЮЧЕН . формат ( АДАПТЕРЫ ПИТАНИЯ [ сам . __name__ ])) def recharge ( self ): если self . соединитель : для состояния в RECHARGE : print ( state ) else : print ( CONNECT_FIRST . format ( POWER_ADAPTERS [ self . __name__ ]))класс IPhoneAdapter ( FormatAndroid ): def __init__ ( self , mobile ): self . mobile = мобильный def recharge ( self ): self . мобильный . перезарядка () def use_micro_usb ( self ): print ( CONNECTED . format ( POWER_ADAPTERS [ "Android" ])) self . мобильный . use_lightning ()класс AndroidRecharger : def __init__ ( self ): self . phone = Android () self . телефон . use_micro_usb () самостоятельно . телефон . перезарядка ()класс IPhoneMicroUSBRecharger : def __init__ ( self ): self . phone = IPhone () self . phone_adapter = IPhoneAdapter ( сам . телефон ) сам . phone_adapter . use_micro_usb () самостоятельно . phone_adapter . перезарядка ()класс IPhoneRecharger : def __init__ ( self ): self . phone = IPhone () self . телефон . use_lightning () себя . телефон . перезарядка ()print ( «Зарядка Android с помощью зарядного устройства MicroUSB.» ) AndroidRecharger () print ()print ( «Зарядка iPhone через MicroUSB с помощью шаблона адаптера.» ) IPhoneMicroUSBRecharger () print ()print ( «Зарядка iPhone с помощью зарядного устройства iPhone.» ) IPhoneRecharger ()
C #
открытый интерфейс ILightningPhone { void ConnectLightning (); void Recharge (); }открытый интерфейс IUsbPhone { void ConnectUsb (); void Recharge (); }публичный запечатанный класс AndroidPhone : IUsbPhone { private bool isConnected ;public void ConnectUsb () { this . isConnected = true ; Консоль . WriteLine ( «Телефон Android подключен.» ); }public void Recharge () { if ( this . isConnected ) { Console . WriteLine ( «Подзарядка телефона Android.» ); } else { Консоль . WriteLine ( «Сначала подключите кабель USB.» ); } } }публичный запечатанный класс ApplePhone : ILightningPhone { private bool isConnected ;public void ConnectLightning () { this . isConnected = true ; Консоль . WriteLine ( «Телефон Apple подключен.» ); }public void Recharge () { if ( this . isConnected ) { Console . WriteLine ( «Подзарядка телефона Apple.» ); } else { Консоль . WriteLine ( «Сначала подключите кабель Lightning.» ); } } }общественного запечатанный класс LightningToUsbAdapter : IUsbPhone { частные чтения ILightningPhone lightningPhone ;private bool isConnected ;public LightningToUsbAdapter ( ILightningPhone lightningPhone ) { this . lightningPhone = lightningPhone ; это . молнияТелефон . ConnectLightning (); }public void ConnectUsb () { this . isConnected = true ; Консоль . WriteLine ( «Переходный кабель подключен.» ); }public void Recharge () { if ( this . isConnected ) { this . молнияТелефон . Пополнить (); } else { Консоль . WriteLine ( «Сначала подключите кабель USB.» ); } } }public void Main () { ILightningPhone applePhone = новый ApplePhone (); IUsbPhone adapterCable = new LightningToUsbAdapter ( applePhone ); адаптер кабель . ConnectUsb (); адаптер кабель . Пополнить (); }
Выход:
Телефон Apple подключен.Кабель адаптера подключен.Зарядка телефона Apple.
Смотрите также
- Адаптер Java Design Patterns - Адаптер
- Делегирование , строго относящееся к шаблону адаптера объекта.
- Принцип инверсии зависимостей , который можно рассматривать как применение шаблона адаптера, когда высокоуровневый класс определяет свой собственный интерфейс (адаптер) для низкоуровневого модуля (реализуемого адаптируемым классом).
- Архитектура портов и адаптеров
- Прокладка
- Функция обертки
- Библиотека обертки
Рекомендации
- ^ a b Фриман, Эрик; Фриман, Элизабет; Сьерра, Кэти ; Бейтс, Берт (2004). Начните с шаблонов проектирования . O'Reilly Media . п. 244. ISBN 978-0-596-00712-6. OCLC 809772256 . Архивировано из оригинала ( в мягкой обложке) по 2013-05-04 . Проверено 30 апреля 2013 .
- ^ Гамма, Эрих; Хелм, Ричард; Джонсон, Ральф; Влиссидес, Джон (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли . С. 139 и далее . ISBN 0-201-63361-2.
- ^ «Шаблон проектирования адаптера - проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 .
- ^ Фриман, Эрик; Фриман, Элизабет; Сьерра, Кэти; Бейтс, Берт (2004). Хендриксон, Майк; Лукидес, Майк (ред.). Head First Design Patterns (мягкая обложка) . 1 . O'Reilly Media . стр. 243, 252, 258, 260. ISBN 978-0-596-00712-6. Проверено 2 июля 2012 .
- ^ «Шаблон проектирования адаптера - структура и взаимодействие» . w3sDesign.com . Проверено 12 августа 2017 .