Lekce 5 - Adapter (wrapper)
V předchozím kvízu, Kvíz - Factory, Singleton, Prototype, Builder ve Vzory GOF, jsme si ověřili nabyté zkušenosti z předchozích lekcí.
V tutoriálu Návrhové vzory GoF si představíme návrhový vzor Adapter, neboli Wrapper. Vzor se používá při práci s komponentou, která má nestabilní nebo s naší aplikací nekompatibilní rozhraní.
Návrhový vzor Adapter umožňuje komponentu obalit naším rozhraním, a tak aplikaci úplně odstínit od rozhraní původního.
Motivace
Většinou při vývoji používáme komponentovou architekturu a využíváme tedy hotových řešení třetích stran (nebo vlastních komponent z předešlých projektů). Představme si, že chceme, nebo dokonce musíme, používat komponentu, které její autoři stále mění rozhraní. My tuto komponentu používáme na 100 místech v programu a při každé nové verzi musíme kód na mnoha místech přepisovat. Podobný problém nastane v případě, když máme v aplikaci již připravené nějaké rozhraní a chceme do něj komponentu zasadit. Ta jednoduše řečeno nepasuje.
Vzor Adapter nám komponentu obalí naším rozhraním. Aplikace je tedy úplně odstíněna od původního rozhraní komponenty. Kdykoli se toto rozhraní změní, stačí aktualizovat pouze Adapter. Díky Adapteru můžeme řešit dokonce i případ, kdy se nám komponenta přestane líbit a vyměníme ji za jinou. Tehdy opět pouze opravíme Adapter a program se zevnitř vůbec nezmění.
Vzor
Vzor je tedy jakýsi prostředník (spojovník) mezi naším rozhraním a rozhraním komponenty, které je pro aplikaci neznámé. Tohoto propojení můžeme dosáhnout na úrovni objektu nebo na úrovni třídy. Vzor má tedy dve varianty.
Object adapter
Podívejme se na grafické znázornění použití vzoru na úrovni objektu:

Klient
je součást našeho systému, která volá naše
rozhraní. Adaptee
je ona komponenta, jejíž rozhraní je
nestabilní, nekompatibilní nebo zkrátka nechceme, aby na něm naše aplikace
byla závislá. Naše rozhraní je definováno v třídě Adapter
,
která zajišťuje transformaci metod od Klient
do
Adaptee
.
Adapter
může být pouze spojovník a volat jen jinak
pojmenované metody. Nebo může obsahovat jednoduchou logiku. Jako příklad si
můžeme představit, že voláme metodu Vloz(tabulka, pole)
,
která se přeloží jako
DatabazovyDotaz('INSERT INTO tabulka VALUES hodnota1, hodnota2...')
.
Pole se transformovalo na jediný parametr a ten je předán
Adaptee
.
Vidíme, že Klient
a Adaptee
jsou propojeny
pomocí objektu Adapter
.
Možná modifikace
Vzor můžeme vylepšit přidáním abstraktní třídy Cil
:

Adapter
nyní dědí z abstraktní třídy Cil
.
Smysl abstraktní třídy je ten, abychom mohli Adapter
snáze
vyměnit za jiný a byli si jisti, že jsme zachovali kompatibilitu. Stejně tak
může být Cil
jen interface.
Class Adapter
Vzor na úrovni třídy bychom graficky zobrazili takto:

Class adapter je méně používaná varianta, protože spoléhá na
skutečnost, že třídu Adaptee
lze dědit.
Výsledný adapter je třída zděděná z Cil
a
Adapter
. Cil
bude samozřejmě interface, aby byla
vícenásobná dědičnost možná. Také ztrácíme možnost pracovat zároveň
s potomky Adaptee
, což by u Object adapteru fungovalo (protože
potomek poskytuje stejné rozhraní, jako předek). Výhodou však je, že
můžeme přepsat některé metody Adaptee
.
Závěrem
Adapter, neboli Wrappery se často staví okolo databází, protože lze poté vyměnit databázi bez jediné změny v naší aplikaci. Nebo pak okolo webových služeb, které mají často složitá API.
V další lekci, Facade (fasáda), si ukážeme návrhový vzor Facade (neboli také Fasádu), který se používá k vytvoření jednotného rozhraní pro celou logickou skupinu tříd.