Adaptér (designový vzor)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 9. března 2016; kontroly vyžadují 47 úprav .
Adaptér
Adaptér

Adaptér zobrazení struktury šablony
Typ strukturální
Účel organizovat používání funkcí objektu, který není k dispozici pro úpravu, prostřednictvím speciálně vytvořeného rozhraní (přenese rozhraní třídy (nebo několika tříd) na rozhraní požadovaného typu)
Platí v případech systém podporuje požadovaná data a chování, ale má nevhodné rozhraní. Nejběžnější použití vzoru Adaptér je, když chcete vytvořit třídu, která je odvozena z nově definované nebo již existující abstraktní třídy.
profesionálové
  • zapouzdření implementace externích tříd (komponent, knihoven), systém se stává nezávislým na rozhraní externích tříd;
  • přechod na použití jiných externích tříd nevyžaduje přepracování samotného systému, stačí implementovat jednu třídu Adapter.
Související šablony Fasáda , dekoratér
Popsáno v Návrhové vzory Ano

Adaptér ( anglicky  Adapter ) je strukturní návrhový vzor navržený k organizaci použití funkcí objektu , který není dostupný pro modifikaci prostřednictvím speciálně vytvořeného rozhraní . Jinými slovy, je to strukturální návrhový vzor, ​​který umožňuje objektům s nekompatibilními rozhraními spolupracovat.

Klíčové vlastnosti

Výzva

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

Řešení

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

Členové

Třída Adaptermapuje rozhraní třídy Adapteena rozhraní třídy Target(které je implementováno třídou Adapter). To umožňuje objektu Clientpoužívat objekt Adaptee(prostřednictvím adaptéru Adapter), jako by to byla instance třídy Target.

Přistupuje tedy Clientk rozhraní Targetimplementovanému třídou Adapter, která přesměruje volání na Adaptee.

Důsledky

Vzor Adaptér umožňuje zahrnutí existujících objektů do nových objektových struktur bez ohledu na rozdíly v jejich rozhraních.

Poznámky a komentáře

Vzor Adaptér umožňuje procesu návrhu ignorovat možné rozdíly v rozhraních existujících tříd. Pokud existuje třída, která má požadované metody a vlastnosti (alespoň koncepčně), pak v případě potřeby můžete vždy pomocí vzoru Adapter uvést její rozhraní do požadované podoby.

V blízkosti Adaptéru je vzor Fasáda , není vždy možné jeden od druhého odlišit [2] .

Použití šablony

Typickým příkladem použití vzoru Adapter je vytváření tříd, které vedou k jedinému rozhraní funkce jazyka PHP , které poskytuje přístup k různým DBMS [3] .

Řešení tohoto problému pomocí šablony Adapter je znázorněno na obrázku.

Implementace

Zahrnutí již existující třídy do jiné třídy. Rozhraní obklopující třídy je aktualizováno, aby vyhovovalo novým požadavkům, a volání jejích metod se převádí na volání metod zahrnuté třídy.


Kroky implementace

  1. Ujistěte se, že máte dvě třídy s nekompatibilními rozhraními:
    • užitečná služba - třída utility, kterou nemůžete změnit (je to buď kód třetí strany, nebo na ní závisí jiný kód);
    • jeden nebo více klientů – existující třídy aplikací, které jsou nekompatibilní se službou kvůli nepohodlnému nebo neodpovídajícímu rozhraní.
  2. Popište klientské rozhraní, jehož prostřednictvím by třídy aplikací mohly používat třídu služeb.
  3. Vytvořte třídu adaptéru implementací tohoto rozhraní.
  4. Umístěte do adaptéru pole, které bude ukládat odkaz na objekt služby. Toto pole je obvykle vyplněno objektem předaným konstruktoru adaptéru. V případě jednoduché adaptace lze tento objekt předat jako parametry metodám adaptéru.
  5. Implementujte všechny metody klientského rozhraní v adaptéru. Adaptér musí delegovat většinu práce na službu.
  6. Aplikace by měla používat adaptér pouze prostřednictvím klientského rozhraní. Díky tomu bude v budoucnu snadné měnit a přidávat adaptéry.


Ruby

Příklad v Ruby modul AdapterPattern # Umožňuje klientovi používat Adaptéry s nekompatibilními rozhraními prostřednictvím Adaptérů s rozhraním Cíl # Adaptee class Twitter def twit udává konec 'Twit byl publikován ' # Adaptee class Facebook def post uvádí 'Facebook příspěvek byl publikován ' konec # Cílový modul WebServiceInterface def send_message raise NotImplementedError end end # Adaptér třídy TwitterAdapter zahrnuje WebServiceInterface def inicializovat @webservice = Twitter . nový konec def send_message @webservice . konec tweetu _ # Adaptér třídy FacebookAdapter obsahuje WebServiceInterface def inicializovat @webservice = Facebook . nový konec def send_message @webservice . příspěvek konec konec # Třída klienta Zpráva attr_accessor :webservice def poslat @webservice . send_message end end def self . spustit vloží '=> Adaptér' zpráva = Zpráva . Nový zpráva . webservice = TwitterAdapter . nová zpráva . poslat zpráva . webová služba = FacebookAdapter . nová zpráva . poslat ukončí ' ' konec Vzor adaptéru . běh

Java - dědičnost

Příklad Java (prostřednictvím dědičnosti) // Cílové veřejné rozhraní Chief { public Object makeBreakfast (); public Object makeLunch (); public Object makeDinner (); } // Adaptee public class Instalatér { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adaptér public class ChiefAdapter extends Instalatér implementuje Chief { public Object makeBreakfast () { return getGasket (); } public Object makeLunch () { return getPipe (); } public Object makeDinner () { return getScrewNut (); } } // Public class klienta Klient { public static void eat ( Object dish ) { ... } public static void main ( String [] args ) { Chief ch = new ChiefAdapter (); Objektová mísa = ch . udělatSnídaně (); jíst ( jídlo ); miska = ch . makeLunch (); jíst ( jídlo ); miska = ch . makeDinner (); jíst ( jídlo ); volejte Ambulance (); } }

Java složení

Příklad Java (přes složení) // Soubor Chief.java public interface Chief { public Object makeSnídaně (); public Object makeDinner (); public Object makeSupper (); } // Soubor Plumber.java public class Instalatér { public Object getPipe () { return new Object (); } public Object getKey () { return new Object (); } public Object getScrewDriver () { return new Object (); } } // Soubor ChiefAdapter.java public class ChiefAdapter implementuje Chief { soukromý Instalatér instalatér = nový Instalatér (); @Override public Object makeBreakfast () { return instalatér . getkey (); } @Override public Object makeDinner () { return instalatér . getScrewDriver (); } @Override public Object makeSupper () { return instalatér . getPipe (); } } // Soubor Client.java public class klient { public static void main ( String [] args ) { Hlavní šéf = nový hlavní adaptér (); Klíč objektu = hlava . makeDinner (); } }

scala

Příklad Scala package object adapter { objekt Battlefield { protected var redTroops : Array [ Vojsko ] = Array () chráněná var blueTroops : Array [ Vojsko ] = Array () def addTroop ( jednotka : Vojsko ) : Jednotka = { if ( jednotka . strana == "červená" ) { červená Vojska :+= jednotka } else if ( jednotka . strana == "modrá" ) { modrá Jednotka :+= jednotka } else { zahoď novou výjimku ( s"Neplatná strana ${ jednotka . strana } pro jednotku ${ jednotka . jméno } " ) } } def getClosestEnemyTroop ( strana : String ): Vojsko = { if ( strana == "červená" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } private def getTroop ( jednotky : Array [ Vojsko ]): Vojsko = { if ( jednotky . délka == 0 ) { hod novou výjimku ( "Žádné dostupné jednotky" ) } jednotky ( 0 ) } } class Vojsko ( strana valu : String , jméno valu : String , val closeZbraň : String , val distanceZbraň : String ) { def move ( direction : String , distance : Int ): Unit = { println ( s" Jméno jednotky $ se pohybuje $ směrem na $ vzdálenost yardů" ) } def attack ( nepřítelská jednotka : Vojsko , typ útoku : Řetězec ) : Jednotka = { val zbraň = typ útoku shoda { případ "vzdálenost" => vzdálenost Pouzdro na zbraň "zavřít" => zavřít pouzdro na zbraň _ => hodit novou výjimku ( s"Neplatný typ útoku $ typ útoku pro oddíl $ name " ) } println ( s" Vojka $ name útočí na nepřátelskou jednotku ${ nepřátelská jednotka . name } svými ${ zbraní } s" ) } } rys LanceKnightTroopTrait { def moveForward ( distance : Int ) : Unit def útok Nejbližší ( typ útoku : Řetězec ) : Jednotka } class LanceKnightTroop ( přepsat stranu valu : String , přepsat val name : String , přepsat val closeZbraň : String , přepsat val distanceWeapon : String ) rozšiřuje oddíl ( strana , jméno , zavřítZbraň , vzdálenostZbraň ) o LanceKnightTroopTrait { override def moveForward ( distance : Int ): Unit = { move ( "forward" , distance ) } override def attackClosest ( attackType : String ): Unit = { attack ( Battlefield . getClosestEnemyTroop ( side ), attackType ) } } object AdapterTest rozšiřuje AbstractTest { override def run (): Unit = { val troop = new Troop ( "modrá" , ​​"Lukostřelci" , "meč" , "dlouhý luk" ) val lanceKnightTroop = new LanceKnightTroop ( "red" , "Lance Knights" , "pike " , kuše ) Bojiště . addTroop ( vojsko ) Battlefield . addTroop ( lanceKnightTroop ) println ( "Výstup:" ) lanceKnightTroop . moveForward ( 300 ) lanceKnightTroop . attackClosest ( "close" ) } } } // Výstup: // Vojsko Lance Knights se pohybuje vpřed o 300 yardů // Vojsko Lance Knights útočí svými štikami na nepřátelské jednotky Archers

PHP5

Příklad v PHP 5 <?php class IndependentDeveloper1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { jméno veřejné funkceIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } } interface IAdapter { public function sum ( $a , $b ); } class ConcreteAdapter1 implementuje IAdapter { protected $object ; public function __construct () { $this -> objekt = new IndependentDeveloper1 (); } public function sum ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } class ConcreteAdapter2 implementuje IAdapter { protected $object ; public function __construct () { $this -> objekt = new IndependentDeveloper2 (); } public function sum ( $a , $b ) { return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b ); } } //na jednom místě vytvoříme konkrétní adaptér a poté použijeme rozhraní $adapter1 = new ConcreteAdapter1 (); $adapter2 = new ConcreteAdapter2 (); /** * Všude v kódu nepoužíváme třídy přímo, ale přes rozhraní * této funkci nezáleží na tom, kterou třídu použijeme, protože se spoléháme na rozhraní * * @param IAdapter $adapter */ function sum ( IAdapter $ adapter ) { echo $ adapter -> sum ( 2 , 2 ); } součet ( $adapter1 ); součet ( $adapter2 );

PHP5.4

Příklad v PHP 5.4 (vlastnost) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class JinýTřída { veřejná funkce jinýSoučet ( $a , $b ) { return $a + $b ; } } vlastnost TAdaptee { public function sum ( int $a , int $b ) { $method = $this -> metoda ; return $this -> $metoda ( $a , $b ); } } class SomeAdaptee rozšiřuje SomeClass { use TAdaptee ; private $method = 'nějakýSoučet' ; } class AnotherAdaptee rozšiřuje AnotherClass { use TAdaptee ; private $method = 'jinýSoučet' ; } $some = new SomeAdaptee ; $další = nový JinýPřizpůsobený ; $nějaké -> součet ( 2 , 2 ); $další -> součet ( 5 , 2 );

PHP5.4 Compact

Příklad v PHP 5.4 (Compact) <?php vlastnost TAdaptee { public function sum ( int $a , int $b ) { $method = $this -> metoda ; return $this -> $metoda ( $a , $b ); } } class SomeClass { use TAdaptee ; private $method = 'nějakýSoučet' ; public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { use TAdaptee ; private $method = 'jinýSoučet' ; veřejná funkce jinýSoučet ( $a , $b ) { return $a + $b ; } } $some = new SomeClass ; $dalsi = novy DalsiClass ; $nějaké -> součet ( 2 , 2 ); $další -> součet ( 5 , 2 );

JavaScript

Příklad JavaScriptu function Hledat ( text , slovo ) { var text = text ; var slovo = slovo ; toto . searchWordInText = function () { return text ; }; toto . getWord = function () { return word ; }; }; function SearchAdapter ( adaptee ) { this . searchWordInText = function () { return 'Tato slova' + adaptee . getWord () + ' nalezené v textu ' + adaptee . searchWordInText (); }; }; var search = new Search ( "text" , "slova" ); var searchAdapter = new SearchAdapter ( hledat ); searchAdapter . searchWordInText ();

Python

Příklad v Pythonu class GameConsole : def create_game_picture ( self ): return 'picture from console' class Antenna : def create_wave_picture ( self ): return 'picture from wave' class SourceGameConsole ( GameConsole ): def get_picture ( self ): return self . create_game_picture () class SourceAntenna ( Antenna ): def get_picture ( self ): return self . create_wave_picture () class TV : def __init__ ( self , zdroj ): self . source = source def show_picture ( self ): return self . zdroj . get_picture () g = SourceGameConsole () a = SourceAntenna () game_tv = TV ( g ) cabel_tv = TV ( a ) print ( game_tv . show_picture ()) print ( cabel_tv . show_picture ())

C# - složení

Příklad C# (složení) pomocí System ; adaptér jmenného prostoru { class MainApp { static void Main () { // Vytvoření adaptéru a zadání požadavku Cílový cíl = nový adaptér (); cíl . žádost (); // Počkejte na uživatelskou konzoli . číst (); } } // "Cílová" class Target { public virtual void Request () { Console . WriteLine ( "Called TargetRequest()" ); } } // "Adaptér" class Adapter : Target { private Adaptee adaptee = new Adaptee (); public override void Request () { // Možná proveďte nějakou jinou práci // a pak zavolejte SpecificRequest adaptee . SpecificRequest (); } } // "Adaptee" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

C# - dědičnost

Příklad C# (dědičnost) pomocí System ; adaptér jmenného prostoru { class MainApp { static void Main () { // Vytvoření adaptéru a zadání požadavku Adaptér adaptér = new Adapter (); adaptér . žádost (); // Počkejte na uživatelskou konzoli . číst (); } } // "Cílová" interface ITarget { public void Request (); } // Můžete použít abstraktní třídu // "Adaptér" class Adapter : Adaptee , ITarget { public void Request () { // Možná udělat nějakou jinou práci // a pak zavolat SpecificRequest SpecificRequest (); } } // "Adaptee" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

Delphi

Příklad Delphi programový adaptér; {$APPTYPE KONZOLE} {$R *.res} používá System.SysUtils; (*Rozhraní pro použití klienta třídy TTarget realizované jako TAdapter*) (*TAdapter přesměruje volání na TAdaptee*) typ TTarget = třída functionRequest:string; virtuální; konec; TAdapte = třída funkce SpecificRequest:string; konec; TAdapter = class(TTarget) fAdaptee: TAdaptee; functionRequest:string; přepsat; konstruktorCreate; konec; { TTarget } funkce TTarget.Request: string; začít Result:= 'Called Target Request()'; konec; {TAdaptee} funkce TAdaptee.SpecificRequest: řetězec; začít Result:= 'Called SpecificRequest()'; konec; {TAdapter} konstruktor TAdapter.Create; začít fAdaptee:= TAdaptee.Create; konec; function TAdapter.Request: string; začít (*Případně udělat nějakou jinou práci a když zavolejte SpecificRequest*) Result:= fAdaptee.SpecificRequest; konec; var target: TTarget; začít Snaž se { TODO -oUser -cConsole Main : Sem vložte kód} (*vytvořit adaptér a zadat požadavek*) target:= TAdapter.Create; WriteLn(target.Request); WriteLn(#13#10+'Pokračujte stisknutím libovolné klávesy...'); ReadLn; target.Free; až na na E: Výjimka do Writeln(E.ClassName, ': ', E.Message); konec; konec.

Poznámky

  1. Blízkost významů pojmů shell a wrapper ( anglicky  wrapper - používá se jako synonymum pro dekoratér) někdy vede k nejasnostem a Adapter je definován jako synonymum pro šablonu Decorator , přičemž se jedná o dvě různé šablony a druhá jmenovaná řeší jiný úkol, a to: připojení dalších povinností k objektu.
  2. Rozdíl je v tom, že vzor Fasáda je navržen tak, aby zjednodušil rozhraní, zatímco vzor Adaptér je navržen tak, aby přinesl různým existujícím rozhraním stejný požadovaný vzhled.
  3. V zastaralých verzích jazyka PHP je přístup do DBMS implementován jako sada funkcí, pro každý DBMS mají jiné názvy a někdy i jinou sadu použitých parametrů, což vede k výrazným problémům při přechodu z jednoho DBMS na jiný, pokud takový přechod není zajištěn předem pomocí šablony Adaptér.

Literatura

  • Alan Shalloway, James R. Trott. Designové vzory. Nový přístup k objektově orientovanému navrhování = vysvětlení návrhových vzorů: Nový pohled na objektově orientovaný design. - M .: "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Techniky objektově orientovaného navrhování. Design Patterns = Design Patterns: Prvky opakovaně použitelného objektově orientovaného softwaru. - Petrohrad. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (také ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Design Patterns = Návrhové vzory Head First. - Petrohrad. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .

Odkazy