Най-простото определение за адаптер е инструмент, който прави възможна работата на два несъвместими интерфейса. Интерфейсите могат да бъдат несъвместими, но вътрешните функционалности трябва да отговарят на приложението. Адаптерът позволява иначе несъвместими класове да работят заедно чрез превръщането на интерфейса на един от класовете в интерфейс с вид, очакван от клиента.
Структура
Съществуват два вида адаптери:
Адаптер на обект. В този случай адаптерът съдържа инстанция на класа, който обвива, като адаптерът извиква инстанцията на обвития обект
Адаптер на класове. Този тип адаптер използва няколко полиморфни интерфейса за имплементиране или наследяване както на интерфейса, който се очаква, така и на интерфейса, който е вече наличен. Характерно за очаквания интерфейс е той да бъде създаден като чист интерфейс клас, особено в езици като Java (преди JDK 1.8), които не поддържат множествено наследяване на класове.
Приложение
Адаптерът е полезен в ситуации, в които един вече съществуващ клас осигурява някои или всички необходими услуги, но не използва необходимия интерфейс. Един добър пример от реалния живот е адаптер, който преобразува интерфейса на Document Object Model на XML документ в дървовидна структура, която може да бъде показана.
Допълнителна форма на изпълнение на Адаптер
Съществува и допълнителна форма на изпълнение на Адаптер както следва:
Казано е за клас А да подаде някакви данни на клас B. Да допуснем, че това са данни от типа низ. Решението за компилация е:
classB.setStringData(classA.getStringData());
Въпреки това, да предположим, че форматът на данните от тип низове трябва да се промени. Решението е да се използва наследяване:
и да се създаде правилно „форматиране“ на обекта по време на изпълнение с помощта на адаптера Factory.
Решение използващо „шаблони“ се изпълнява по следния начин:
(i) дефиниране на посредник „Доставчик“ интерфейс, изписване имплементация за изпълнение на този „Доставчик“ интерфейс, който обвива източника на данните (Class A В този пример) и извеждане данните форматирани по целесъобразност:
publicinterfaceStringProvider{publicStringgetStringData();}publicclassClassAFormat1implementsStringProvider{privateClassAclassA=null;publicClassAFormat1(finalClassAA){classA=A;}publicStringgetStringData(){returnformat(classA.getStringData());}privateStringformat(StringsourceValue){//манипулира низът-източник във//формат, който се изисква от обекта, нуждаещ се от информацията на//обекта-източникreturn sourceValue.trim();}}
(ii) изписване на адаптер клас, който връща характерната имплементация на „Доставчика“:
(vii) По този начин използването на адаптери и доставчици позволява множество „изгледи“ от клас C и клас A към клас B, без да се налага да се променя йерархията на класа. Като цяло, това позволява механизма за произволни потоци данни между обекти да бъдат монтирани на съществуваща йерархия.
Изпълнение на адаптер модела
При прилагането на адаптер за по-голяма яснота може да се прилага името на класа [име на класа] до [Interface] адаптера за прилагане на имплементацията. За пример – DAOToProviderAdapter. Тя трябва да има метод конструктор с променлива от тип adaptee като параметър. Този параметър ще бъде приет за член на инстанция на [име на класа] до [Interface] адаптер. Когато clientMethod се извика той ще има достъп до adaptee инстанцията, която дава възможност за достъп до необходимите данни на adaptee и извършване на операции по тези данни, което генерира желания изход.
implicitdefadaptee2Adapter(adaptee:Adaptee):Adapter={newAdapter{overridedefclientMethod:Unit={// повиква метода/и на Adaptee, за да осъществи clientMethod на Клиента. */}}}
Лепило код
Терминът лепило код понякога се използва за описване на реализации на модела на адаптера. Тя не допринася на изчисленията или компилацията. Тя по-скоро служи като прокси между иначе несъвместими части на софтуер, за да ги направят съвместими. Стандартната практика е да се запази логиката на лепило кода и да се остави това на кода към който се свързва.
JavaScript (пример за Адаптер шаблон на JavaScript)
functionSearch(text,word){vartext=text;varword=word;this.searchWordInText=function(){returntext;};this.getWord=function(){returnword;};};functionSearchAdapter(adaptee){this.searchWordInText=function(){return'Тези думи '+adaptee.getWord()+' намерени в текста '+adaptee.searchWordInText();};};varsearch=newSearch("текст","думи")varsearchAdapter=newSearchAdapter(search);searchAdapter.searchWordInText();
classGameConsole:defcreate_game_picture(self):return'picture from console'classAntenna:defcreate_wave_picture(self):return'picture from wave'classSourceGameConsole(GameConsole):defget_picture(self):returnself.create_game_picture()classSourceAntenna(Antenna):defget_picture(self):returnself.create_wave_picture()classTV:def__init__(self,source):self.source=sourcedefshow_picture(self):returnself.source.get_picture()g=SourceGameConsole()a=SourceAntenna()game_tv=TV(g)cabel_tv=TV(a)printgame_tv.show_picture()printcabel_tv.show_picture()
usingSystem;namespaceAdapter{classMainApp{staticvoidMain(){// Create adapter and place a requestTargettarget=newAdapter();target.Request();// Wait for userConsole.Read();}}// "Target"classTarget{publicvirtualvoidRequest(){Console.WriteLine("Called Target Request()");}}// "Adapter"classAdapter:Target{privateAdapteeadaptee=newAdaptee();publicoverridevoidRequest(){// Possibly do some other work// and then call SpecificRequestadaptee.SpecificRequest();}}// "Adaptee"classAdaptee{publicvoidSpecificRequest(){Console.WriteLine("Called SpecificRequest()");}}}