Připravený kód pro adaptéry v jazyce Java. Návrhový vzor adaptéru

    Hlavní článek: Adaptér (návrhový vzor) Příklad implementace vzoru v C# pomocí System; Adaptér jmenného prostoru ( třída MainApp ( static void Main() ( ... Wikipedie

    Tento termín má jiné významy, viz Vzor. Při vývoji softwaru je návrhový vzor opakovatelný architektonický návrh, který představuje řešení problému... ... Wikipedie

    Rozhraní návrhového vzoru Rozhraní popsané v návrhových vzorech Ne V informatice není vzor rozhraní zvláštním vzorem mezi návrhovými vzory. Je to obecná metoda pro strukturování počítačových programů za účelem... Wikipedie

    Proxy vzor návrhový vzor. Poskytuje objekt pro řízení přístupu a zachycuje všechna volání k němu. Obsah 1 Cíl 1.1 Problém 1.2 Řešení 2 Klady 3 ... Wikipedie

    Návrhový vzor Guardian Memento Typ: Behaviorální Popsáno v návrhových vzorech Ano Guardian (také známý jako Memento, Token, Token) je behaviorální návrhový vzor. Umožňuje opravit bez porušení zapouzdření... Wikipedie

    Typ iterátoru návrhového vzoru: chování Popsané v návrhových vzorech Ano Vzor iterátoru (také známý jako kurzor) Návrhový vzor, ​​který odkazuje na vzory chování. Je to objekt, který vám umožňuje získat ... Wikipedie

    Návrhový vzor Interpreter Typ: behaviorální Účel: řeší často se vyskytující problém náchylný ke změnám Popsáno v Design Patterns Ano Interpret pattern (anglicky ... Wikipedia

    Návrhový vzor Kompozitní Typ: strukturální Popsáno v Návrhových vzorech Ano Kompozitní vzor je návrhový vzor, ​​odkazuje na strukturální vzory, kombinuje objekt ... Wikipedia

    Návrhový vzor Typ stavu: behaviorální Popsáno v Návrhové vzory Ano Stav je návrhový vzor. Používá se v případech, kdy během provádění programu dojde k objektu ... Wikipedie

Vraťme se k úvahám o konstrukčních vzorech. Tentokrát se podíváme na designový vzor tzv Adaptér(společně se vzorem Fasáda se také nazývá Wrapper).

V tomto článku budeme hovořit o následujícím:

Vzor Adaptér se tedy používá k tomu, aby objekty s jedním rozhraním (smlouvou) mohly pracovat tam, kde je potřeba objekt s úplně jiným rozhraním. Existují dva typy adaptérů – Class Adapter a Object Adapter.

Nejprve se podíváme na každý z těchto typů a poté vysvětlím rozdíl mezi dvěma obaly – adaptérem a fasádou.

Objektový adaptér

Object Adapter dosahuje svého cíle prostřednictvím kompozice. V níže uvedeném diagramu musí klient používat rozhraní TargetInterface. K tomu je vytvořena třída ObjectAdapter, která implementuje rozhraní TargetInterface a také ukládá objekt třídy Adaptee. Při volání metody targetMethod na adaptéru se zavolá odpovídající metoda na přizpůsobovaném rozhraní.

V nejjednodušším případě by implementace ObjectAdapteru vypadala takto:

Veřejná třída ObjectAdapter implementuje TargetInterface ( private Adaptee adaptee; public void targetMethod() ( adaptee.method() ) )

Výhodou tohoto přístupu je, že zcela oddělíme klientské rozhraní od adaptabilního rozhraní.

Adaptér třídy

V případě Class Adapter se k dosažení našeho cíle používá vícenásobná dědičnost Náš ClassAdapter dědí z klientského rozhraní az rozhraní Adaptable Protože v Javě neexistuje vícenásobná dědičnost, pouze jeden z předků může být abstraktní/konkrétní třída. Druhým předkem bude rozhraní, což není vždy pohodlné.

Diagram třídy:

A zde je triviální implementace třídy ClassAdapter:

Veřejná třída ClassAdapter rozšiřuje Adaptee implementuje TargetInterface ( public void targetMethod() ( method(); ) )

Rád bych upozornil na skutečnost, že při takové implementaci adaptéru může dojít ke konfliktu v signaturách metod. Objektový adaptér tento problém nemá.

Class Adapter je považován za jednodušší řešení, když není vyžadováno striktní oddělení klienta a adaptabilních rozhraní.

Rozdíl mezi adaptérem a fasádou

Nyní bych chtěl říci pár slov o vzoru Fasáda, který, stejně jako Adaptér, definuje Fasáda Nový rozhraní, když je adaptér používán existující rozhraní.

Neměli byste srovnávat Facade a Adapter takto: říkají, že Facade může zabalit několik tříd, ale Adapter přizpůsobí pouze jednu. Velmi dobře se může stát, že adaptér bude potřeba k přizpůsobení několika tříd a naopak, fasáda bude muset být použita ke zjednodušení pouze jedné komplexní třídy. Rozdíl mezi těmito dvěma vzory tedy není v počtu entit, které jsou zabaleny, ale v tom, proč to dělají.

Příklad použití adaptéru v JDK

Příklady použití Adaptéru můžete také najít ve standardní knihovně. Pravděpodobně nejoblíbenějším případem použití je java.io.InputStreamReader a OutputStreamWriter.

Konstruktor InputStreamReader bere InputStream jako vstup a v důsledku toho přizpůsobuje proud do čtečky.

Později zveřejním kód pro použití adaptérů ze skutečných projektů, na kterých jsem se podílel, ale zatím čekám na vaše dotazy a komentáře. Hodně štěstí.

Účel

Adaptér(Angličtina) Adaptér nebo anglicky Obal-Wrapper) je strukturní návrhový vzor určený k organizaci použití funkcí objektu, který není k dispozici pro modifikaci prostřednictvím speciálně vytvořeného rozhraní.

Úkol

Systém podporuje požadovaná data a chování, ale má nevhodné rozhraní.

Řešení

Adaptér umožňuje vytvoření obalové třídy s požadovaným rozhraním.

Účastníci

Třída Adapter mapuje rozhraní třídy Adaptee na rozhraní třídy cílová(jehož je Adapter nástupcem). To umožňuje objektu Client používat objekt Adaptee (prostřednictvím adaptéru), jako by to byla instance třídy. cílová.

Tímto způsobem klient přistupuje k rozhraní cílová, implementovaný v nástupci Adapter, který přesměruje volání na Adaptee.

Diagram tříd UML vzoru Adaptér

Důsledky

Vzor Adaptér umožňuje začlenit existující objekty do nových objektových struktur bez ohledu na rozdíly v jejich rozhraních.

Popis

Třída, jejíž rozhraní je potřeba upravit do požadované podoby, nechť se jmenuje Adaptee. K vyřešení problému transformace jeho rozhraní zavádí vzor Adapter následující hierarchii tříd:

    Cílová virtuální základní třída. Zde je deklarováno uživatelské rozhraní příslušného druhu. Uživateli je k dispozici pouze toto rozhraní.

    Odvozená třída Adaptéru, která implementuje rozhraní Target. Tato třída také obsahuje ukazatel nebo odkaz na instanci Adaptee. Vzor Adaptér používá tento ukazatel k předávání klientských volání na Adaptee. Protože rozhraní Adaptee a Target jsou vzájemně nekompatibilní, tato volání obvykle vyžadují konverzi.

Vzor Adapter, který je softwarovým obalem existujících tříd, převádí jejich rozhraní do formy vhodné pro následné použití.

Podívejme se na jednoduchý příklad, kdy je vhodné použít vzor Adaptér. Dovolte nám vyvinout klimatizační systém navržený tak, aby automaticky udržoval okolní teplotu ve stanovených mezích. Důležitou součástí takového systému je teplotní senzor, který měří okolní teplotu pro následnou analýzu. Pro tento senzor již existuje hotový software od vývojářů třetích stran, což je určitá třída s odpovídajícím rozhraním. Tuto třídu však nemůžete použít přímo, protože naměřené hodnoty senzoru se odečítají ve stupních Fahrenheita. Potřebujete adaptér, který převádí teplotu na stupně Celsia.

Implementace

adaptér jmenného prostoru

statické void Main()

// Vytvořte adaptér a zadejte požadavek

Cílový cíl = nový adaptér();

target.Request();

// Počkejte na uživatele

veřejná virtuální void požadavek()

Console.WriteLine("Called Target Request()");

Adaptér třídy: Cíl

private Adaptee adaptee = new Adaptee();

veřejné přepsání void Request()

// Možná udělat nějakou jinou práci

// a poté zavolejte SpecificRequest

adaptee.SpecificRequest();

public void SpecificRequest()

Console.WriteLine("Called SpecificRequest()");

Výsledky použití vzoru Adaptér

Výhody vzoru Adaptér

    Vzor Adaptér vám umožňuje znovu použít existující kód úpravou jeho nekompatibilního rozhraní do použitelné podoby.

Nevýhody vzoru adaptéru

    Úloha převodu rozhraní může být obtížná, pokud volání klienta a/nebo předávané parametry nemají funkční shodu v přizpůsobovaném objektu.

    Adaptér (Design Pattern)/Příklady kódu- Hlavní článek: Adaptér (návrhový vzor) Příklad implementace vzoru v C# pomocí System; Adaptér jmenného prostoru ( třída MainApp ( static void Main() ( ... Wikipedie

    Proxy vzor (návrhový vzor)

    Návrhový vzor- Tento termín má jiné významy, viz Vzor. Při vývoji softwaru je návrhový vzor opakovatelný architektonický návrh, který představuje řešení problému... ... Wikipedie

    Rozhraní (designový vzor)- Rozhraní návrhového vzoru popsané v návrhových vzorech Ne V informatice není vzor rozhraní zvláštním vzorem mezi návrhovými vzory. Je to obecná metoda pro strukturování počítačových programů za účelem... Wikipedie

    Zástupce (návrhový vzor)- Proxy vzor (zástupce) Návrhový vzor. Poskytuje objekt pro řízení přístupu a zachycuje všechna volání k němu. Obsah 1 Cíl 1.1 Problém 1.2 Řešení 2 Klady 3 ... Wikipedie

    Guardian (designový vzor)- Design Pattern Guardian Memento Typ: Behaviorální Popsaný v Design Patterns Ano Guardian (také známý jako Memento, Token, Token) je behaviorální designový vzor. Umožňuje opravit bez porušení zapouzdření... Wikipedie

    Iterátor (návrhový vzor)- Typ iterátoru návrhového vzoru: behaviorální Popsáno v návrhových vzorech Ano Vzor iterátoru (také známý jako kurzor) Návrhový vzor, ​​který odkazuje na vzorce chování. Je to objekt, který vám umožňuje získat ... Wikipedie

    Tlumočník (designový vzor)- Návrhový vzor Interpreter Typ: behaviorální Účel: řeší často se vyskytující problém náchylný ke změnám Popsáno v Design Patterns Ano Interpreter Pattern (anglicky ... Wikipedia

    Linker (designový vzor)- Návrhový vzor Kompozitní Typ: strukturální Popsáno v Návrhových vzorech Ano Kompozitní vzor je návrhový vzor, ​​odkazuje na strukturální vzory, kombinuje objekt ... Wikipedia

    Stav (návrhový vzor)- Stavový návrhový vzor Typ: behaviorální Popsáno v Návrhové vzory Ano Stav je návrhový vzor. Používá se v případech, kdy během provádění programu dojde k objektu ... Wikipedie

Adaptér vzoru, obal

Název vzoru a klasifikace

Adaptér je vzor, ​​který strukturuje třídy i objekty.

Účel vzoru adaptéru

Nový softwarový projekt často nedokáže znovu použít stávající kód. Například existující třídy mohou mít požadovanou funkčnost, ale mají nekompatibilní rozhraní. V takových případech byste měli použít vzor Adaptér k převodu rozhraní jedné třídy na rozhraní jiné, které klienti očekávají.

Vzor Adapter, který je softwarovým obalem existujících tříd, převádí jejich rozhraní do formy vhodné pro následné použití.

Podívejme se na nejjednodušší příklad použití vzoru Adaptér Pojďme vyvinout systém klimatizace. Důležitou součástí takového systému je teplotní čidlo, pro které existuje již hotový software, což je určitá třída s odpovídajícím rozhraním pro práci s Fahrenheitovou stupnicí. Nás ale zajímá teplota na Celsiově stupnici. Problém lze snadno vyřešit pomocí vzoru Adaptér

Uvažujme další příklad - grafický editor, ve kterém mohou uživatelé kreslit grafické prvky (čáry, polygony, text atd.) na obrazovku a organizovat je ve formě obrázků a diagramů. Hlavní abstrakcí grafického editoru je grafický objekt, který má proměnlivý tvar a zobrazuje sám sebe. Rozhraní grafických objektů je definováno abstraktní třídou Shape. Editor definuje podtřídu třídy Shape pro každý typ grafického objektu: LineShape pro čáry, PolygonShape pro polygony atd.

Třídy pro základní geometrické tvary, jako jsou LineShape a PolygonShape, jsou relativně snadno implementovatelné, protože jejich vlastní možnosti kreslení a úprav jsou extrémně omezené. Ale podtřída Text Shape, která umí zobrazovat a upravovat text, je mnohem složitější. Zároveň existují hotové knihovny pro vývoj uživatelských rozhraní, které poskytují vyvinutou třídu Text View pro zobrazování a úpravy textu.

Bylo by možné změnit rozhraní třídy Text View tak, aby odpovídalo rozhraní Shape, ale to by vyžadovalo zdrojový kód. Ale i když je k dispozici, je stěží moudré měnit zobrazení textu - knihovna by se neměla přizpůsobovat rozhraním každé konkrétní aplikace.

Místo toho můžete definovat třídu Text Shape tak, že bude přizpůsobit Rozhraní Text View k rozhraní Shape. To lze provést dvěma způsoby: dědění rozhraní od Shape a implementace z textového zobrazení; zahrnutím instance zobrazení textu do tvaru textu a implementací tvaru textu z hlediska rozhraní zobrazení textu. Tyto dva přístupy odpovídají variantám vzoru Adapter v jeho třídních a objektových formách. Zavoláme třídu Text Shape (obr. 40) Adaptér.

Diagram ukazuje objektový adaptér. Můžete vidět, jak je požadavek BoundingBox deklarovaný ve třídě Shape přeložen do požadavku Get Extent definovaného ve třídě Text View. Protože třída Text Shape přizpůsobuje zobrazení textu rozhraní Shape, může grafický editor použít třídu TextView, i když má nekompatibilní rozhraní.

Adaptér je často zodpovědný za funkčnost, kterou adaptující třída nemůže poskytnout. Na Obr. 40 zobrazený jako adaptér

return newTextManipulator^^

Rýže. 40. UML diagram objektového adaptéru

vykonává takové funkce. Uživatel by měl mít možnost přesunout jakýkoli objekt Shape na jiné místo, ale třída TextView takovou operaci neposkytuje. Text Shape může přidat chybějící funkcionalitu implementací operace CreateManipulator samotné třídy Shape, která vrátí instanci příslušné podtřídy Manipulator.

Manipulátor je abstraktní třída objektů, která ví, jak animovat tvar v reakci na akce uživatele, jako je přetažení tvaru na jiné místo. Třída Manipulátor má podtřídy pro různé tvary. Například TextManipulator je podtřída Text Shape. Vrácením instance TextManipulator přidává objekt třídy TextShape nové funkce, které třída TextView nemá, ale třída Shape vyžaduje.

Použitelnost

Použijte vzor adaptéru, když:

  • chcete použít existující třídu, ale její rozhraní nevyhovuje vašim potřebám;
  • chystáte se vytvořit znovu použitelnou třídu, která musí interagovat s dříve neznámými nebo nesouvisejícími třídami, které mají nekompatibilní rozhraní;
  • (pouze pro objektový adaptér!) je třeba použít několik existujících podtříd, ale je nepraktické přizpůsobovat jejich rozhraní vytvářením nových podtříd z každé. V tomto případě může objektový adaptér přizpůsobit rozhraní jejich společné rodičovské třídy.

Popis vzoru adaptéru

Adaptér třídy používá vícenásobnou dědičnost k přizpůsobení jednoho rozhraní druhému.

Třída, jejíž rozhraní je potřeba upravit do požadované podoby, nechť má jméno Přizpůsobit se. K vyřešení problému transformace jeho rozhraní zavádí vzor Adapter následující hierarchii tříd:

  • virtuální základní třída Cílová. Zde je deklarováno uživatelské rozhraní příslušného druhu. Uživateli je k dispozici pouze toto rozhraní;
  • odvozená třída Adaptér, který implementuje rozhraní Target. Tato třída také obsahuje ukazatel nebo odkaz na instanci Přizpůsobit se. Vzor Adaptér používá tento ukazatel k přesměrování volání klientů na Přizpůsobit se. Vzhledem k tomu, rozhraní Přizpůsobit se A cílová jsou vzájemně nekompatibilní, tyto hovory obvykle vyžadují konverzi.

Struktura

Struktura vzoru adaptéru je znázorněna na obr. 41.

Objektový adaptér vynucuje složení objektu.


adaptee->specificRequest()

Rýže. 41. Diagram tříd UML vzoru Adaptér

Účastníci

Cíl (tvar) - cíl: definuje rozhraní specifické pro doménu, které klient používá.

Klient (DrawingEditor) - klient: vstupuje do vztahů s objekty, které vyhovují rozhraní Target.

Adapt?e (Textview) - Adaptable: Definuje existující rozhraní, které je třeba upravit.

Adaptér (Text Shape) - Adaptér: přizpůsobuje rozhraní Adapt?e cílovému rozhraní.

Vztah

Klienti vyvolávají operace na instanci Adaptéru. Adaptér zase zavolá operace adaptabilního objektu nebo třídy Adapt?e, která provede požadavek.

Výsledek

Výsledky použití objektových a třídních adaptérů se liší.

Adaptér třídy:

  • přizpůsobuje Adapt?e cíli a deleguje akce na konkrétní třídu Adapt?e. Proto tento vzor nebude fungovat, pokud chceme současně přizpůsobit třídu a její podtřídy;
  • umožňuje Adaptéru přepsat některé operace adaptabilní třídy Adapt?e, protože Adapter není nic jiného než podtřída Adapt?e;
  • představuje pouze jeden nový objekt. Abyste se dostali k adaptabilní třídě, není potřeba žádný další ukazatel.

Objektový adaptér:

  • umožňuje jednomu Adaptéru pracovat s mnoha adaptabilními objekty, to znamená samotným Adaptérem a jeho podtřídami (pokud existují). Adaptér může přidat novou funkcionalitu všem přizpůsobitelným objektům najednou;
  • ztěžuje nahrazení operací třídy Adapt?e. To by vyžadovalo podtřídu Adapt?e a přimět Adapter odkazovat se na tuto podtřídu spíše než na Adapt?e samotnou.

Adaptéry se značně liší v množství práce potřebné k přizpůsobení rozhraní Adapt?e cílovému rozhraní. To může být tak jednoduché jako transformace, jako je změna názvů operací nebo podpora úplně jiné sady operací. Množství práce závisí na tom, jak se od sebe liší rozhraní cílové a adaptabilní třídy.

V prvním kroku implementace je nutné najít „úzké“ rozhraní pro Adapt?, tedy nejmenší podmnožinu operací, která umožňuje přizpůsobení. „Úzké“ rozhraní sestávající pouze z několika iterací se snadněji přizpůsobuje než rozhraní skládající se z několika desítek operací.

„Úzké“ rozhraní lze implementovat různými způsoby.

  • 1. Použití abstraktních operací. Podtřídy musí implementovat tyto abstraktní operace a přizpůsobit hierarchicky strukturovaný objekt.
  • 2. Použití objektů proxy. S tímto přístupem jsou požadavky na přístup k hierarchické struktuře předávány objektu oprávnění.

Klasická implementace vzoru Adapter

Zde je implementace vzoru Adaptér. Ve výše uvedeném příkladu přizpůsobujeme hodnoty teplotního senzoru systému klimatizace a převádíme je ze stupňů Fahrenheita na stupně Celsia (předpokládá se, že kód pro tento senzor není k dispozici pro úpravu).

// Již existující třída snímače okolní teploty

třída FahrenheitSensor

// Získání hodnot teploty ve stupních Fahrenheita float getFahrenheitTemp() ( float t = 32,0;

//... nějaký kód vrátí t;

virtuální ~Sensor()()

třída Adaptér: veřejný senzor

Adaptér(FahrenheitSensor* p): p_fsensor(p) (

Adapted) ( delete p_fsensor;

float getTemperature() ( return (p_fsensor->getFahrenheitTemp()-32.0)*5.0/9.0;

FahrenheitSensor* p_fsensor;

Senzor* p = nový adaptér (nový FahrenheitSensor);

cout getTemperature()

Implementace vzoru Adaptér na základě uzavřené dědičnosti

Nechte náš snímač teploty systému klimatizace podporovat funkci nastavení pro přesnější údaje. Tuto funkci není nutné používat, což je pravděpodobně důvod, proč je odpovídající metoda adjust() prohlášena za chráněnou vývojáři ve stávající třídě FahrenheitSensor.

Systém, který vyvíjíme, musí podporovat přizpůsobení měření. Vzhledem k tomu, že přístup k chráněné metodě přes ukazatel nebo odkaz je zakázán, klasická implementace vzoru Adapter zde již není vhodná. Jediným řešením je dědit z třídy FahrenheitSensor. Rozhraní této třídy musí zůstat pro uživatele nepřístupné, takže dědictví musí být soukromé.

Cíle sledované při použití otevřené a uzavřené dědičnosti jsou různé. Zatímco otevřená dědičnost se používá pro dědění rozhraní a implementace, uzavřená dědičnost se používá pouze pro dědění implementace.

třída FahrenheitSensor

float getFahrenheitTempO ( float t = 32,0;

void adjustQ() // Upravte senzor (chráněná metoda)

virtuální ~Sensor()()

virtuální plovoucí getTemperature() = 0;

virtuální void adjust() = 0;

Adaptér třídy: veřejný senzor, soukromý senzor FahrenheitSensor

Adapter() () float getTemperature() ( return (getFahrenheitTemp()-32.0)*5.0/9.0;

FahrenheitSensor::adjust();

Senzor * p = new Adapter(); p->upravit();

cout getTemperature()

Výsledky použití vzoru Adaptér

Výhody vzoru Adaptér

Vzor Adaptér vám umožňuje znovu použít existující kód úpravou jeho nekompatibilního rozhraní do použitelné podoby.

Nevýhody vzoru adaptéru

Úloha převodu rozhraní může být obtížná, pokud volání klienta a/nebo předávané parametry nemají funkční shodu v přizpůsobovaném objektu.

Související vzory

Struktura vzoru Bridge je podobná struktuře Adaptéru, ale Bridge má jiný účel. Odděluje rozhraní od implementace, takže obě lze nezávisle měnit. Adaptér je určen ke změně rozhraní existující objekt.

Vzor Dekorátor rozšiřuje funkčnost objektu změnou jeho rozhraní. Dekorátor je tedy pro aplikaci transparentnější než Adaptér. V důsledku toho Decorator podporuje rekurzivní kompozici, což u „čistých“ adaptérů není možné.

Proxy definuje zástupce nebo zástupce jiného objektu, ale nemění jeho rozhraní.