Adaptér vzor - Adapter pattern
![]() | tento článek může obsahovat nerozlišující, nadměrnýnebo irelevantní příklady.Ledna 2011) ( |
v softwarové inženýrství, vzor adaptéru je vzor návrhu softwaru (také známý jako wrapper, alternativní pojmenování sdílené s dekoratér vzor ), který umožňuje rozhraní existujícího třída použít jako další rozhraní.[1] Často se používá k tomu, aby existující třídy fungovaly s ostatními, aniž by upravovaly své zdrojový kód.
Příkladem je adaptér, který převádí rozhraní a Model objektu dokumentu z XML dokument do stromové struktury, kterou lze zobrazit.
Přehled
Adaptér[2] designový vzor je jedním z dvaceti tří známých GoF návrhové vzory které popisují, jak řešit opakující se konstrukční problémy při navrhování flexibilního a opakovaně použitelného objektově orientovaného softwaru, tj. objektů, které se snadněji implementují, mění, testují a znovu používají.
Návrhový vzor adaptéru řeší problémy jako:[3]
- Jak lze znovu použít třídu, která nemá rozhraní, které vyžaduje klient?
- Jak mohou třídy, které mají nekompatibilní rozhraní, spolupracovat?
- Jak lze pro třídu poskytnout alternativní rozhraní?
Třídu (již existující) nelze často znovu použít pouze proto, že její rozhraní neodpovídá požadavkům, které klienti vyžadují.
Návrhový vzor adaptéru popisuje, jak tyto problémy vyřešit:
- Definujte samostatný
adaptér
třída, která převádí (nekompatibilní) rozhraní třídy (přizpůsobit
) do jiného rozhraní (cílová
) klienti vyžadují. - Projděte si
adaptér
pracovat s (znovu použít) třídami, které nemají požadované rozhraní.
Klíčovou myšlenkou v tomto vzoru je propracovat se samostatně adaptér
který přizpůsobuje rozhraní (již existující) třídy beze změny.
Klienti neví, zda pracují s cílová
třídy přímo nebo prostřednictvím adaptér
s třídou, která nemá cílová
rozhraní.
Viz také diagram tříd UML níže.
Definice
Adaptér umožňuje spolupráci dvou nekompatibilních rozhraní. Toto je skutečná definice adaptéru. Rozhraní mohou být nekompatibilní, ale vnitřní funkčnost by měla vyhovovat potřebám. Návrhový vzor adaptéru umožňuje jinak nekompatibilním třídám spolupracovat převedením rozhraní jedné třídy na rozhraní očekávané klienty.
Používání
Adaptér lze použít, když modul wrapper musí respektovat určité rozhraní a musí podporovat polymorfní chování. Alternativně a natěrač umožňuje přidat nebo změnit chování rozhraní za běhu, a fasáda se používá, když je požadováno jednodušší nebo jednodušší rozhraní k podkladovému objektu.[4]
Vzor | Úmysl |
---|---|
Adaptér nebo obal | Převede jedno rozhraní na druhé tak, aby odpovídalo očekávání klienta |
Natěrač | Dynamicky přidává odpovědnost rozhraní zabalením původního kódu |
Delegace | Podpora „složení nad dědičností“ |
Fasáda | Poskytuje zjednodušené rozhraní |
Struktura
Diagram tříd UML

Ve výše uvedeném UML třídní diagram, klient
třída, která vyžaduje a cílová
rozhraní nemůže znovu použít přizpůsobit
třída přímo, protože její rozhraní neodpovídá cílová
místo toho klient
pracuje přes adaptér
třída, která implementuje cílová
rozhraní ve smyslu přizpůsobit
:
- The
adaptér objektu
způsobem implementujecílová
rozhraní delegováním napřizpůsobit
objekt za běhu (adaptee.specificOperation ()
). - The
adaptér třídy
způsobem implementujecílová
rozhraní zděděním zpřizpůsobit
třída v době kompilace (specificOperation ()
).
Vzor adaptéru objektu
V tomto vzoru adaptéru obsahuje adaptér instanci třídy, kterou zabalí. V této situaci adaptér provádí volání instance zabaleného objekt.


Vzor adaptéru třídy
Tento vzor adaptéru používá více polymorfní rozhraní implementace nebo zdědění rozhraní, které se očekává, a rozhraní, které již existuje. Je typické, že očekávané rozhraní bude vytvořeno jako čisté rozhraní třída, zejména v jazyky jako Jáva (před JDK 1.8), které nepodporují vícenásobné dědictví tříd.[1]


Další forma vzorce běhového adaptéru
Motivace z časového řešení kompilace
Je to žádoucí pro třída A.
dodávat třída B.
s některými údaji, předpokládejme, že některá Tětiva
data. Řešení kompilace je:
třída B..setStringData(třída A..getStringData());
Předpokládejme však, že formát dat řetězce musí být změněn. Řešením v době kompilace je použití dědičnosti:
veřejnost třída Format1ClassA rozšiřuje Třída A. { @ Přepis veřejnost Tětiva getStringData() { vrátit se formát(toString()); }}
a možná vytvořte správně "formátovaný" objekt za běhu pomocí tovární vzor.
Běhové řešení adaptéru
Řešení využívající „adaptéry“ probíhá následovně:
(i) definovat zprostředkující rozhraní „poskytovatele“ a napsat implementaci tohoto rozhraní poskytovatele, která zabalí zdroj dat, Třída A.
v tomto příkladu a odešle data formátovaná podle potřeby:
veřejnost rozhraní StringProvider { veřejnost Tětiva getStringData();}veřejnost třída ClassAFormat1 nářadí StringProvider { soukromé Třída A. třída A. = nula; veřejnost ClassAFormat1(finále Třída A. A) { třída A. = A; } veřejnost Tětiva getStringData() { vrátit se formát(třída A..getStringData()); } soukromé Tětiva formát(finále Tětiva sourceValue) { // Manipulujte se zdrojovým řetězcem do požadovaného formátu // objektem, který potřebuje data zdrojového objektu vrátit se sourceValue.čalounění(); }}
(ii) Napište třídu adaptéru, která vrací konkrétní implementaci poskytovatele:
veřejnost třída ClassAFormat1Adapter rozšiřuje Adaptér { veřejnost Objekt přizpůsobit se(finále Objekt objekt) { vrátit se Nový ClassAFormat1((Třída A.) objekt); }}
(iii) Zaregistrujte adaptér
s globálním registrem, takže adaptér
lze vyhledat za běhu:
Továrna adaptéru.getInstance().registerAdapter(Třída A..třída, ClassAFormat1Adapter.třída, „format1“);
(iv) V kódu, pokud si přejete přenést data z Třída A.
na Třída B.
, psát si:
Adaptér adaptér = Továrna adaptéru.getInstance() .getAdapterFromTo(Třída A..třída, StringProvider.třída, „format1“);StringProvider poskytovatel = (StringProvider) adaptér.přizpůsobit se(třída A.);Tětiva tětiva = poskytovatel.getStringData();třída B..setStringData(tětiva);
nebo výstižněji:
třída B..setStringData( ((StringProvider) Továrna adaptéru.getInstance() .getAdapterFromTo(Třída A..třída, StringProvider.třída, „format1“) .přizpůsobit se(třída A.)) .getStringData());
(v) Výhodu lze vidět v tom, že pokud je žádoucí přenášet data ve druhém formátu, vyhledejte jiný adaptér / poskytovatele:
Adaptér adaptér = Továrna adaptéru.getInstance() .getAdapterFromTo(Třída A..třída, StringProvider.třída, „format2“);
(vi) A pokud je žádoucí odeslat data z Třída A.
jako, řekněme, obrazová data v Třída C
:
Adaptér adaptér = Továrna adaptéru.getInstance() .getAdapterFromTo(Třída A..třída, ImageProvider.třída, „format2“);ImageProvider poskytovatel = (ImageProvider) adaptér.přizpůsobit se(třída A.);třída C..setImage(poskytovatel.getImage());
(vii) Tímto způsobem umožňuje použití adaptérů a poskytovatelů několik „pohledů“ od Třída B.
a Třída C.
do Třída A.
aniž byste museli měnit hierarchii tříd. Obecně to umožňuje mechanismus pro libovolné datové toky mezi objekty, které lze dovybavit existující hierarchií objektů.
Implementace vzoru adaptéru
Při implementaci vzoru adaptéru lze pro přehlednost použít název třídy [Jméno třídy]Na[Rozhraní]Adaptér
k implementaci poskytovatele; například, DAOToProviderAdapter
. Měla by mít metodu konstruktoru s proměnnou třídy adaptability jako parametr. Tento parametr bude předán členu instance [Jméno třídy]Na[Rozhraní]Adaptér
. Když se volá clientMethod, bude mít přístup k instanci adaptéru, která umožňuje přístup k požadovaným datům adaptéru a provádění operací s těmito daty, která generují požadovaný výstup.
Jáva
rozhraní LightningPhone { prázdnota dobít(); prázdnota použít blesk();}rozhraní MicroUsbPhone { prázdnota dobít(); prázdnota useMicroUsb();}třída Iphone nářadí LightningPhone { soukromé booleovský konektor; @ Přepis veřejnost prázdnota použít blesk() { konektor = skutečný; Systém.ven.tisk(„Blesk připojen“); } @ Přepis veřejnost prázdnota dobít() { -li (konektor) { Systém.ven.tisk(„Dobíjení spuštěno“); Systém.ven.tisk(„Dobití dokončeno“); } jiný { Systém.ven.tisk(„Nejprve připojte blesk“); } }}třída Android nářadí MicroUsbPhone { soukromé booleovský konektor; @ Přepis veřejnost prázdnota useMicroUsb() { konektor = skutečný; Systém.ven.tisk(„MicroUsb připojeno“); } @ Přepis veřejnost prázdnota dobít() { -li (konektor) { Systém.ven.tisk(„Dobíjení spuštěno“); Systém.ven.tisk(„Dobití dokončeno“); } jiný { Systém.ven.tisk(„Nejprve připojte MicroUsb“); } }}/ * vystavení cílového rozhraní při zabalení zdrojového objektu * /třída LightningToMicroUsbAdapter nářadí MicroUsbPhone { soukromé finále LightningPhone bleskPhone; veřejnost LightningToMicroUsbAdapter(LightningPhone bleskPhone) { tento.bleskPhone = bleskPhone; } @ Přepis veřejnost prázdnota useMicroUsb() { Systém.ven.tisk(„MicroUsb připojeno“); bleskPhone.použít blesk(); } @ Přepis veřejnost prázdnota dobít() { bleskPhone.dobít(); }}veřejnost třída Adaptér Demo { statický prázdnota dobítMicroUsbPhone(MicroUsbPhone telefon) { telefon.useMicroUsb(); telefon.dobít(); } statický prázdnota dobít LightningPhone(LightningPhone telefon) { telefon.useLightning(); telefon.dobít(); } veřejnost statický prázdnota hlavní(Tětiva[] args) { Android Android = Nový Android(); Iphone iPhone = Nový Iphone(); Systém.ven.tisk(„Dobíjení Androidu pomocí MicroUsb“); dobítMicroUsbPhone(Android); Systém.ven.tisk(„Dobíjení iPhone bleskem“); dobít LightningPhone(iPhone); Systém.ven.tisk(„Dobíjení iPhone pomocí MicroUsb“); dobítMicroUsbPhone(Nový LightningToMicroUsbAdapter (iPhone)); }}
Výstup
Dobíjení Androidu s MicroUsbMicroUsb připojeno Nabíjení spuštěno Dobíjení dokončeno Dobíjení iPhonu pomocí Lightning Lightning připojeno Dobíjení dokončeno Dobíjení iPhone dobíjeno pomocí MicroUsbMicroUsb připojeno Lightning připojeno Dobíjení spuštěno Dobíjení dokončeno
Krajta
"""Příklad vzoru adaptéru."""z abc import ABCMeta, abstraktní metodaNENÍ IMPLEMENTOVÁNO = „Měli byste to implementovat.“DOBÍJENÍ = [„Dobíjení začalo.“, „Dobití dokončeno.“]NAPÁJECÍ ADAPTÉRY = {„Android“: „MicroUSB“, „iPhone“: "Blesk"}PŘIPOJENO = "{} připojeno. “CONNECT_FIRST = "Připojit {} za prvé."třída RechargeTemplate: __metaclass__ = ABCMeta @abstractmethod def dobít(já): vyzdvihnout NotImplementedError(NENÍ IMPLEMENTOVÁNO)třída Formát IPhone(RechargeTemplate): @abstractmethod def use_lightning(já): vyzdvihnout NotImplementedError(NENÍ IMPLEMENTOVÁNO)třída FormatAndroid(RechargeTemplate): @abstractmethod def use_micro_usb(já): vyzdvihnout NotImplementedError(NENÍ IMPLEMENTOVÁNO)třída IPhone(Formát IPhone): __název__ = „iPhone“ def __init__(já): já.konektor = Nepravdivé def use_lightning(já): já.konektor = Skutečný tisk(PŘIPOJENO.formát(NAPÁJECÍ ADAPTÉRY[já.__název__])) def dobít(já): -li já.konektor: pro Stát v DOBÍJENÍ: tisk(Stát) jiný: tisk(CONNECT_FIRST.formát(NAPÁJECÍ ADAPTÉRY[já.__název__]))třída Android(FormatAndroid): __název__ = „Android“ def __init__(já): já.konektor = Nepravdivé def use_micro_usb(já): já.konektor = Skutečný tisk(PŘIPOJENO.formát(NAPÁJECÍ ADAPTÉRY[já.__název__])) def dobít(já): -li já.konektor: pro Stát v DOBÍJENÍ: tisk(Stát) jiný: tisk(CONNECT_FIRST.formát(NAPÁJECÍ ADAPTÉRY[já.__název__]))třída IPhoneAdaptér(FormatAndroid): def __init__(já, mobilní, pohybliví): já.mobilní, pohybliví = mobilní, pohybliví def dobít(já): já.mobilní, pohybliví.dobít() def use_micro_usb(já): tisk(PŘIPOJENO.formát(NAPÁJECÍ ADAPTÉRY[„Android“])) já.mobilní, pohybliví.use_lightning()třída AndroidRecharger: def __init__(já): já.telefon = Android() já.telefon.use_micro_usb() já.telefon.dobít()třída IPhoneMicroUSBRecharger: def __init__(já): já.telefon = IPhone() já.telefon_adaptér = IPhoneAdaptér(já.telefon) já.telefon_adaptér.use_micro_usb() já.telefon_adaptér.dobít()třída IPhoneRecharger: def __init__(já): já.telefon = IPhone() já.telefon.use_lightning() já.telefon.dobít()tisk(„Dobíjení Androidu pomocí MicroUSB nabíječky.“)AndroidRecharger()tisk()tisk("Dobíjení iPhone pomocí MicroUSB pomocí vzoru adaptéru.")IPhoneMicroUSBRecharger()tisk()tisk(„Dobíjení iPhone pomocí nabíječky iPhone.“)IPhoneRecharger()
Viz také
- Adaptér Java Design Patterns - Adaptér
- Delegace, silně relevantní pro vzor adaptéru objektu.
- Princip inverze závislostí, což lze považovat za použití adaptéru, když třída na vysoké úrovni definuje vlastní (adaptér) rozhraní pro modul na nízké úrovni (implementováno třídou adaptee).
- Architektura portů a adaptérů
- Podložka
- Funkce obálky
- Knihovna obalů
Reference
- ^ A b Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hlava první návrhové vzory. O'Reilly Media. p. 244. ISBN 978-0-596-00712-6. OCLC 809772256. Archivovány od originál (brožura) dne 04.05.2013. Citováno 2013-04-30.
- ^ Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Návrhové vzory: Prvky opakovaně použitelného objektově orientovaného softwaru. Addison Wesley. str.139ff. ISBN 0-201-63361-2.
- ^ „Návrhový vzor adaptéru - problém, řešení a použitelnost“. w3sDesign.com. Citováno 2017-08-12.
- ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Hlava první návrhové vzory (brožura). 1. O'Reilly Media. 243, 252, 258, 260. ISBN 978-0-596-00712-6. Citováno 2012-07-02.
- ^ „Návrhový vzor adaptéru - struktura a spolupráce“. w3sDesign.com. Citováno 2017-08-12.