Адаптер, Adapter — структурний шаблон проєктування, призначений для організації використання функцій об'єкту, недоступного для модифікації, через спеціально створений інтерфейс.
Призначення
Адаптує інтерфейс одного класу в інший, очікуваний клієнтом. Адаптер забезпечує роботу класів з несумісними інтерфейсами, та найчастіше застосовується тоді, коли система підтримує необхідні дані і поведінку, але має невідповідний інтерфейс.
Застосування
Адаптер передбачає створення класу-оболонки з необхідним інтерфейсом.
Структура
Учасники
Клас Adapter
приводить інтерфейс класу Adaptee
у відповідність з інтерфейсом класу Target
(спадкоємцем якого є Adapter
). Це дозволяє об'єктові Client
використовувати об'єкт Adaptee
так, немов він є екземпляром класу Target
.
Наслідки
Шаблон Адаптер дозволяє включати вже наявні об'єкти в нові об'єктні структури, незалежно від відмінностей в їхніх інтерфейсах.
Переваги та недоліки
Переваги
- Допомагає досягти багаторазового використання та гнучкості.
- Клас клієнта не ускладнюється необхідністю використовувати інший інтерфейс і може використовувати поліморфізм для обміну між різними реалізаціями адаптерів.
Недоліки
- Всі запити пересилаються, тому спостерігається незначне збільшення накладних витрат.
- Іноді багато адаптацій потрібні по ланцюгу адаптера, щоб досягти потрібного типу.
Зв'язок з іншими патернами
- Фасад створює новий інтерфейс доступу, адаптер — використовує старий
Реалізація
Інтерфейс класу Adaptee
, тобто того, який адаптується, приводиться у відповідність з новими вимогами класу Target
, а виклики його методів перетворяться у виклики методів класу Target
.
Шаблон Адаптер для адаптації інтерфейсу методу/ів Adaptee
до інтерфейсу Target
в Adapter
можна реалізувати як мінімум двома способами: використовуючи композицію+успадкування (Адаптер об'єкта), або використовуючи множинне успадкування (Адаптер класу).
- Адаптер об'єкта:
Adapter
наслідує інтерфейс відTarget
(успадкування) та містить примірник (здебільшого як вказівник) класуAdaptee
(композиція) і делегує виклики своїх методів (які збігаються з інтерфейсомTarget
) доAdaptee
- Адаптер класу:
Adapter
наслідує інтерфейси обох класівTarget
таAdaptee
(множинне успадкування). В ООП-мовах, які не підтримують множинне успадкування, реалізація цього варіанту адаптера дещо складніша (наприклад в Java за допомогою інтерфейсів).
C++
#include <iostream> using namespace std; // Target Ціль struct CShape { virtual ~CShape() {}; virtual void Draw() { cout << "Rectangle" << endl; }; }; // Adaptee Будемо адаптувати struct CTextViewer { CTextViewer() {}; virtual ~CTextViewer() {}; void DrawText() { cout << "Text" << endl; }; }; // Adapter // Адаптер класу struct CTextShape : public CShape, protected CTextViewer { CTextShape() {}; virtual ~CTextShape() {}; virtual void Draw() { DrawText(); // Виклик метода класу, що адаптуємо }; }; // Адаптер об’єкта struct CTextShapeOBJ // : public CShape { CTextViewer shape; virtual void Draw() { shape.DrawText(); // Виклик метода класу, що адаптуємо }; }; // Client void DrawObject(CShape* p) { p->Draw(); } void main() { // Створюємо адаптер і малюємо об'єкт CShape* obj = new CTextShape(); DrawObject(obj); delete obj; CTextShapeOBJ adapt; CTextViewer obj2; adapt.shape = obj2; adapt.Draw(); }
Java
interface LightningPhone { void recharge(); void useLightning(); } interface MicroUsbPhone { void recharge(); void useMicroUsb(); } class Iphone implements LightningPhone { private boolean connector; @Override public void useLightning() { connector = true; System.out.println("Lightning connected"); } @Override public void recharge() { if (connector) { System.out.println("Recharge started"); System.out.println("Recharge finished"); } else { System.out.println("Connect Lightning first"); } } } class Android implements MicroUsbPhone { private boolean connector; @Override public void useMicroUsb() { connector = true; System.out.println("MicroUsb connected"); } @Override public void recharge() { if (connector) { System.out.println("Recharge started"); System.out.println("Recharge finished"); } else { System.out.println("Connect MicroUsb first"); } } } /* exposing the target interface while wrapping source object */ class LightningToMicroUsbAdapter implements MicroUsbPhone { private final LightningPhone lightningPhone; public LightningToMicroUsbAdapter(LightningPhone lightningPhone) { this.lightningPhone = lightningPhone; } @Override public void useMicroUsb() { System.out.println("MicroUsb connected"); lightningPhone.useLightning(); } @Override public void recharge() { lightningPhone.recharge(); } } public class AdapterDemo { static void rechargeMicroUsbPhone(MicroUsbPhone phone) { phone.useMicroUsb(); phone.recharge(); } static void rechargeLightningPhone(LightningPhone phone) { phone.useLightning(); phone.recharge(); } public static void main(String[] args) { Android android = new Android(); Iphone iPhone = new Iphone(); System.out.println("Recharging android with MicroUsb"); rechargeMicroUsbPhone(android); System.out.println("Recharging iPhone with Lightning"); rechargeLightningPhone(iPhone); System.out.println("Recharging iPhone with MicroUsb"); rechargeMicroUsbPhone(new LightningToMicroUsbAdapter (iPhone)); } }
Output
Recharging android with MicroUsb MicroUsb connected Recharge started Recharge finished Recharging iPhone with Lightning Lightning connected Recharge started Recharge finished Recharging iPhone with MicroUsb MicroUsb connected Lightning connected Recharge started Recharge finished
Зауваження і коментарі
Шаблон Адаптер дозволяє в процесі проєктування не брати до уваги можливі відмінності в інтерфейсах вже наявних класів. Якщо є клас, що володіє необхідними методами і властивостями (принаймні, концептуально), то при необхідності завжди можна скористатися шаблоном Адаптер для приведення його інтерфейсу до потрібного вигляду.
Більш прийнятним є адаптер об'єкта, в якому використовується композиція+успадкування, оскільки це більш відповідає правилу "надавайте перевагу композиції, а не успадкуванню". Цей адаптер можна використовувати тільки односторонньо — як заміну для Target. Однак, у випадку, коли ми створюємо двосторонній адаптер, або ж адаптер, який адаптує одночасно кілька Adaptee класів, слід надавати перевагу шаблону адаптера класу. Також адаптер класу дозволяє більш ефективно використовувати вже реалізований код з Target та Adaptee. Однак недоліки адаптера класу випливають з множинного успадкування, коли зміни в деяких базових класах викликають непередбачливі зміни в похідних, а особливо, коли це відбувається одночасно в кількох успадкованих адаптером класах.
Близьким Адаптеру є шаблон Фасад, не завжди можна відрізнити один від другого. Різниця полягає в тому, що шаблон Фасад призначений для спрощення інтерфейсу і створює новий інтерфейс, тоді як шаблон Адаптер використовує з обох сторін інтерфейси, які є в наявності, і забезпечує їх функціювання.
Відомі застосування
Типовим прикладом використання шаблону Адаптер можна назвати створення класів, що приводять до єдиного інтерфейсу функції мови PHP що забезпечують доступ до різних СУБД.
Примітки
- В мові PHP доступ до СУБД реалізований у вигляді набору функцій, для кожної СУБД вони мають різні найменування і, іноді, різний набір використовуваних параметрів, що приводить до значних проблем при переході з однією СУБД на іншу, якщо такий перехід наперед не забезпечений використанням шаблону Адаптер.
Джерела
- Adapter pattern [ 13 жовтня 2007 у Wayback Machine.]
- Design Patterns: Elements of Reusable Object-Oriented Software [ 9 листопада 2012 у Wayback Machine.]
- Чим відрізняється декоратор від адаптера? (І про фасад) [ 22 грудня 2014 у Wayback Machine.] - Блог одного кібера
Література
Алан Шаллоуей, Джеймс Р. Тротт. Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М. : «Вильямс», 2002. — 288 с. — .
Вікіпедія, Українська, Україна, книга, книги, бібліотека, стаття, читати, завантажити, безкоштовно, безкоштовно завантажити, mp3, відео, mp4, 3gp, jpg, jpeg, gif, png, малюнок, музика, пісня, фільм, книга, гра, ігри, мобільний, телефон, android, ios, apple, мобільний телефон, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Інтернет
Adapter Adapter strukturnij shablon proyektuvannya priznachenij dlya organizaciyi vikoristannya funkcij ob yektu nedostupnogo dlya modifikaciyi cherez specialno stvorenij interfejs PriznachennyaAdaptuye interfejs odnogo klasu v inshij ochikuvanij kliyentom Adapter zabezpechuye robotu klasiv z nesumisnimi interfejsami ta najchastishe zastosovuyetsya todi koli sistema pidtrimuye neobhidni dani i povedinku ale maye nevidpovidnij interfejs ZastosuvannyaAdapter peredbachaye stvorennya klasu obolonki z neobhidnim interfejsom StrukturaUML diagrama sho ilyustruye strukturu shablonu proyektuvannya Adapter z vikoristannyam mnozhinnogo nasliduvannya UchasnikiKlas Adapter privodit interfejs klasu Adaptee u vidpovidnist z interfejsom klasu Target spadkoyemcem yakogo ye Adapter Ce dozvolyaye ob yektovi Client vikoristovuvati ob yekt Adaptee tak nemov vin ye ekzemplyarom klasu Target NaslidkiShablon Adapter dozvolyaye vklyuchati vzhe nayavni ob yekti v novi ob yektni strukturi nezalezhno vid vidminnostej v yihnih interfejsah Perevagi ta nedolikiPerevagi Dopomagaye dosyagti bagatorazovogo vikoristannya ta gnuchkosti Klas kliyenta ne uskladnyuyetsya neobhidnistyu vikoristovuvati inshij interfejs i mozhe vikoristovuvati polimorfizm dlya obminu mizh riznimi realizaciyami adapteriv Nedoliki Vsi zapiti peresilayutsya tomu sposterigayetsya neznachne zbilshennya nakladnih vitrat Inodi bagato adaptacij potribni po lancyugu adaptera shob dosyagti potribnogo tipu Zv yazok z inshimi paternamiFasad stvoryuye novij interfejs dostupu adapter vikoristovuye starijRealizaciyaInterfejs klasu Adaptee tobto togo yakij adaptuyetsya privoditsya u vidpovidnist z novimi vimogami klasu Target a vikliki jogo metodiv peretvoryatsya u vikliki metodiv klasu Target Shablon Adapter dlya adaptaciyi interfejsu metodu iv Adaptee do interfejsu Target v Adapter mozhna realizuvati yak minimum dvoma sposobami vikoristovuyuchi kompoziciyu uspadkuvannya Adapter ob yekta abo vikoristovuyuchi mnozhinne uspadkuvannya Adapter klasu Adapter ob yekta Adapter nasliduye interfejs vid Target uspadkuvannya ta mistit primirnik zdebilshogo yak vkazivnik klasu Adaptee kompoziciya i deleguye vikliki svoyih metodiv yaki zbigayutsya z interfejsom Target do Adaptee Adapter klasu Adapter nasliduye interfejsi oboh klasiv Target ta Adaptee mnozhinne uspadkuvannya V OOP movah yaki ne pidtrimuyut mnozhinne uspadkuvannya realizaciya cogo variantu adaptera desho skladnisha napriklad v Java za dopomogoyu interfejsiv C Priklad realizaciyi na movi S include lt iostream gt using namespace std Target Cil struct CShape virtual CShape virtual void Draw cout lt lt Rectangle lt lt endl Adaptee Budemo adaptuvati struct CTextViewer CTextViewer virtual CTextViewer void DrawText cout lt lt Text lt lt endl Adapter Adapter klasu struct CTextShape public CShape protected CTextViewer CTextShape virtual CTextShape virtual void Draw DrawText Viklik metoda klasu sho adaptuyemo Adapter ob yekta struct CTextShapeOBJ public CShape CTextViewer shape virtual void Draw shape DrawText Viklik metoda klasu sho adaptuyemo Client void DrawObject CShape p p gt Draw void main Stvoryuyemo adapter i malyuyemo ob yekt CShape obj new CTextShape DrawObject obj delete obj CTextShapeOBJ adapt CTextViewer obj2 adapt shape obj2 adapt Draw Java Priklad realizaciyi na movi Java interface LightningPhone void recharge void useLightning interface MicroUsbPhone void recharge void useMicroUsb class Iphone implements LightningPhone private boolean connector Override public void useLightning connector true System out println Lightning connected Override public void recharge if connector System out println Recharge started System out println Recharge finished else System out println Connect Lightning first class Android implements MicroUsbPhone private boolean connector Override public void useMicroUsb connector true System out println MicroUsb connected Override public void recharge if connector System out println Recharge started System out println Recharge finished else System out println Connect MicroUsb first exposing the target interface while wrapping source object class LightningToMicroUsbAdapter implements MicroUsbPhone private final LightningPhone lightningPhone public LightningToMicroUsbAdapter LightningPhone lightningPhone this lightningPhone lightningPhone Override public void useMicroUsb System out println MicroUsb connected lightningPhone useLightning Override public void recharge lightningPhone recharge public class AdapterDemo static void rechargeMicroUsbPhone MicroUsbPhone phone phone useMicroUsb phone recharge static void rechargeLightningPhone LightningPhone phone phone useLightning phone recharge public static void main String args Android android new Android Iphone iPhone new Iphone System out println Recharging android with MicroUsb rechargeMicroUsbPhone android System out println Recharging iPhone with Lightning rechargeLightningPhone iPhone System out println Recharging iPhone with MicroUsb rechargeMicroUsbPhone new LightningToMicroUsbAdapter iPhone Output Recharging android with MicroUsb MicroUsb connected Recharge started Recharge finished Recharging iPhone with Lightning Lightning connected Recharge started Recharge finished Recharging iPhone with MicroUsb MicroUsb connected Lightning connected Recharge started Recharge finishedZauvazhennya i komentariShablon Adapter dozvolyaye v procesi proyektuvannya ne brati do uvagi mozhlivi vidminnosti v interfejsah vzhe nayavnih klasiv Yaksho ye klas sho volodiye neobhidnimi metodami i vlastivostyami prinajmni konceptualno to pri neobhidnosti zavzhdi mozhna skoristatisya shablonom Adapter dlya privedennya jogo interfejsu do potribnogo viglyadu Bilsh prijnyatnim ye adapter ob yekta v yakomu vikoristovuyetsya kompoziciya uspadkuvannya oskilki ce bilsh vidpovidaye pravilu nadavajte perevagu kompoziciyi a ne uspadkuvannyu Cej adapter mozhna vikoristovuvati tilki odnostoronno yak zaminu dlya Target Odnak u vipadku koli mi stvoryuyemo dvostoronnij adapter abo zh adapter yakij adaptuye odnochasno kilka Adaptee klasiv slid nadavati perevagu shablonu adaptera klasu Takozh adapter klasu dozvolyaye bilsh efektivno vikoristovuvati vzhe realizovanij kod z Target ta Adaptee Odnak nedoliki adaptera klasu viplivayut z mnozhinnogo uspadkuvannya koli zmini v deyakih bazovih klasah viklikayut neperedbachlivi zmini v pohidnih a osoblivo koli ce vidbuvayetsya odnochasno v kilkoh uspadkovanih adapterom klasah Blizkim Adapteru ye shablon Fasad ne zavzhdi mozhna vidrizniti odin vid drugogo Riznicya polyagaye v tomu sho shablon Fasad priznachenij dlya sproshennya interfejsu i stvoryuye novij interfejs todi yak shablon Adapter vikoristovuye z oboh storin interfejsi yaki ye v nayavnosti i zabezpechuye yih funkciyuvannya Vidomi zastosuvannyaTipovim prikladom vikoristannya shablonu Adapter mozhna nazvati stvorennya klasiv sho privodyat do yedinogo interfejsu funkciyi movi PHP sho zabezpechuyut dostup do riznih SUBD PrimitkiV movi PHP dostup do SUBD realizovanij u viglyadi naboru funkcij dlya kozhnoyi SUBD voni mayut rizni najmenuvannya i inodi riznij nabir vikoristovuvanih parametriv sho privodit do znachnih problem pri perehodi z odniyeyu SUBD na inshu yaksho takij perehid napered ne zabezpechenij vikoristannyam shablonu Adapter DzherelaAdapter pattern 13 zhovtnya 2007 u Wayback Machine Design Patterns Elements of Reusable Object Oriented Software 9 listopada 2012 u Wayback Machine Chim vidriznyayetsya dekorator vid adaptera I pro fasad 22 grudnya 2014 u Wayback Machine Blog odnogo kiberaLiteraturaAlan Shallouej Dzhejms R Trott Shablony proektirovaniya Novyj podhod k obektno orientirovannomu analizu i proektirovaniyu Design Patterns Explained A New Perspective on Object Oriented Design M Vilyams 2002 288 s ISBN 0 201 71594 5