Adaptor (model de design)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 9 martie 2016; controalele necesită 47 de modificări .
Adaptor
Adaptor

Adaptor de vizualizare a structurii șablonului
Tip de structural
Scop pentru a organiza utilizarea funcțiilor unui obiect care nu este disponibil pentru modificare printr-o interfață special creată (aduce interfața unei clase (sau a mai multor clase) la interfața de tipul dorit)
Se aplică în cazuri sistemul acceptă datele și comportamentul necesar, dar are o interfață necorespunzătoare. Cea mai frecventă utilizare a modelului Adaptor este atunci când doriți să creați o clasă care derivă dintr-o clasă abstractă nou definită sau deja existentă.
pro
  • încapsularea implementării claselor externe (componente, biblioteci), sistemul devine independent de interfața claselor externe;
  • trecerea la utilizarea altor clase externe nu necesită reelaborarea sistemului în sine, este suficient să implementați o clasă Adapter.
Șabloane înrudite Fatada , Decorator
Descris în Design Patterns da

Adaptor ( eng.  Adapter ) este un model de proiectare structural conceput pentru a organiza utilizarea funcțiilor unui obiect care nu este disponibil pentru modificare printr-o interfață special creată . Cu alte cuvinte, este un model de design structural care permite obiectelor cu interfețe incompatibile să lucreze împreună.

Caracteristici cheie

Provocare

Sistemul acceptă datele și comportamentul necesar, dar are o interfață inadecvată.

Soluție

Adaptorul prevede crearea unei clase de wrapper [1] cu interfața necesară.

Membrii

O clasă Adaptermapează o interfață de clasă Adapteela o interfață de clasă Target(care este implementată de clasă Adapter). Acest lucru permite obiectului să Clientfolosească obiectul Adaptee(prin adaptor Adapter) ca și cum ar fi o instanță a clasei Target.

Accesează astfel Clientinterfața Targetimplementată de clasa Adaptercare redirecționează apelul către Adaptee.

Consecințele

Modelul Adaptor permite ca obiectele existente să fie incluse în noi structuri de obiecte, indiferent de diferențele dintre interfețele lor.

Note și comentarii

Modelul Adaptor permite procesului de proiectare să ignore posibilele diferențe în interfețele claselor existente. Dacă există o clasă care are metodele și proprietățile necesare (cel puțin conceptual), atunci, dacă este necesar, puteți utiliza oricând modelul Adaptor pentru a-și aduce interfața la forma dorită.

Aproape de adaptor este modelul Fațadei , nu este întotdeauna posibil să se distingă unul de celălalt [2] .

Aplicarea unui șablon

Un exemplu tipic de utilizare a modelului Adaptor este crearea de clase care conduc la o singură interfață a unei funcții de limbaj PHP care oferă acces la diferite SGBD [3] .

O soluție la această problemă folosind șablonul Adaptor este prezentată în figură.

Implementare

Includerea unei clase deja existente într-o altă clasă. Interfața clasei incluse este actualizată pentru a îndeplini noile cerințe, iar apelurile la metodele sale sunt convertite în apeluri la metodele clasei incluse.


Etape de implementare

  1. Asigurați-vă că aveți două clase cu interfețe incompatibile:
    • serviciu util - o clasă de utilitate pe care nu o poți modifica (este fie terță parte, fie alt cod depinde de ea);
    • unul sau mai mulți clienți - clase de aplicații existente care sunt incompatibile cu serviciul din cauza unei interfețe incomode sau nepotrivite.
  2. Descrieți interfața client prin care clasele de aplicații ar putea folosi clasa de serviciu.
  3. Creați o clasă de adaptor prin implementarea acestei interfețe.
  4. Plasați un câmp în adaptor care va stoca o referință la obiectul de serviciu. De obicei, acest câmp este populat cu obiectul transmis constructorului adaptorului. În cazul adaptării simple, acest obiect poate fi trecut ca parametri la metodele adaptoare.
  5. Implementați toate metodele de interfață client în adaptor. Adaptorul trebuie să delege cea mai mare parte a lucrării serviciului.
  6. Aplicația ar trebui să utilizeze adaptorul numai prin interfața client. Acest lucru va facilita schimbarea și adăugarea adaptoarelor în viitor.


Ruby

Exemplu în Ruby module AdapterPattern # Permite clientului să utilizeze Adaptees cu interfețe incompatibile prin Adaptoare cu interfață țintă # Adaptee clasa Twitter def twit pune „Twit a fost publicat” la sfârșitul sfârșitului # Adaptee clasa Facebook def post pune „Postarea Facebook a fost publicată” la sfârșitul sfârșitului # Modulul țintă WebServiceInterface def send_message raise NotImplementedError end end # Clasa adaptor TwitterAdapter include WebServiceInterface def initialize @webservice = Twitter . sfârşit nou def send_message @webservice . Sfârșitul sfârșitului tweetului # Clasa adaptor FacebookAdapter include WebServiceInterface def initialize @webservice = Facebook . sfârşit nou def send_message @webservice . sfârșitul post - sfârșit # Clasa client Mesaj attr_accessor :webservice def trimite @webservice . send_message end end def sine . run puts '=> Adaptor' mesaj = Mesaj . nou mesaj . serviciu web = TwitterAdapter . mesaj nou . trimite mesaj . webservice = FacebookAdapter . mesaj nou . trimite pune '' end end AdaptorPattern . alerga

Java - moștenire

Exemplu Java (prin moștenire) // Target public interface Chief { public Object makeBreakfast (); public Object makeLunch (); Public Object makeDinner (); } // Adaptee public class Instalator { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adaptor public class ChiefAdapter se extinde Instalator implementa Chief { public Object makeBreakfast () { return getGasket (); } public Object makeLunch () { return getPipe (); } public Object makeDinner () { return getScrewNut (); } } // Client public class Client { public static void eat ( Object dish ) { ... } public static void main ( String [] args ) { Chief ch = new ChiefAdapter (); Farfurie obiect = ch . faceMicul dejun (); mănâncă ( mâncare ); farfurie = ch . facePrânzul (); mănâncă ( mâncare ); farfurie = ch . faceCina (); mănâncă ( mâncare ); apelAmbulanță (); } }

Compoziția Java

Exemplu Java (prin compoziție) // Fișierul Chief.java Șef interfață publică { Public Object makeBreakfast (); Public Object makeDinner (); Public Object makeSupper (); } // Fișier Plumber.java Instalator de clasă publică { public Object getPipe () { return new Object (); } public Object getKey () { return new Object (); } public Object getScrewDriver () { return new Object (); } } // Fișierul ChiefAdapter.java Clasa publică ChiefAdapter implementează Chief { instalator instalator privat = instalator nou (); @Override public Object makeBreakfast () { return plumber . getkey (); } @Override public Object makeDinner () { return instalator . getScrewDriver (); } @Override public Object makeSupper () { return instalator . getPipe (); } } // Fișier client.java clasă publică client { public static void main ( String [] args ) { Chief chief = new ChiefAdapter (); Cheie obiect = cap . faceCina (); } }

scala

exemplu Scala adaptor obiect pachet { obiect Battlefield { protected var redTroops : Array [ Troop ] = Array () protected var blueTroops : Array [ Troop ] = Array () def addTroop ( trupă : Trupă ) : Unitate = { dacă ( trupă . partea == " roșu " ) { Trupe roșii :+= trupă } else if ( trupă . parte == " albastru " ) { Trupe albastre :+= trupă } else { aruncă o nouă excepție ( s"Partea invalidă ${ trupă . latură } pentru trupă ${ trupă . nume } " ) } } def getClosestEnemyTroop ( side : String ): Troop = { if ( side == "red" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } private def getTroop ( trupe : Array [ Troop ]): Troop = { if ( trupe . lungime == 0 ) { throw new Exception ( „Nu există trupe disponibile” ) } trupe ( 0 ) } } clasa Trupa ( latura val : String , nume val : String , val closeWeapon : String , val distanceWeapon : String ) { def mutare ( direcție : String , distanță : Int ): Unit = { println ( s" Numele trupei $ mută $ direcție pe $ distanță metri " ) } def attack ( enemyTroop : Troop , attackType : String ) : Unit = { val weapon = attackType match { case "distance" => distanceWeapon case "close" => closeWeapon case _ => arunca o nouă Excepție ( s"Tip de atac nevalid $ attackType pentru trupa $ nume " ) } println ( s"Trupa $ name atacă trupa inamică ${ enemyTroop . name } cu ${ armele } lor" ) } } trăsătură LanceKnightTroopTrait { def moveForward ( distanta : Int ) : Unit def attackClosest ( attackType : String ) : Unit } clasa LanceKnightTroop ( override val side : String , override val name : String , override val closeWeapon : String , override val distanceWeapon : String ) extinde Troop ( side , name , closeWeapon , distanceWeapon ) cu LanceKnightTroopTrait { override def moveForward ( distanta : Int ): Unit = { mutare ( " inainte " , distanta ) } override def attackClosest ( attackType : String ): Unit = { attack ( Battlefield . getClosestEnemyTroop ( side ), attackType ) } } obiect AdapterTest extinde AbstractTest { override def run (): Unitate = { val trupă = trupă nouă ( " albastru " , " Arcași " , " sabie " , " arc lung " ) val lanceKnightTroop = nou LanceKnightTroop ( " roșu " , " Lance Knights " , " știucă " , arbaleta ) Câmp de luptă . addTroop ( trupă ) Câmp de luptă . addTroop ( lanceKnightTroop ) println ( "Ieșire:" ) lanceKnightTroop . mută înainte ( 300 ) lanceKnightTroop . atacClosest ( „închidere” ) } } } // Ieșire: // Troop Lance Knights înaintează cu 300 de metri // Troop Lance Knights atacă arcașii trupei inamice cu stiuțele lor

PHP5

Exemplu în PHP 5 <?php class IndependentDeveloper1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { public function nameIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } } interfață IAdapter { public function sum ( $a , $b ); } clasa ConcreteAdapter1 implementează IAdapter { protected $object ; function public __construct () { $this -> object = new IndependentDeveloper1 (); } public function sum ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } clasa ConcreteAdapter2 implementează IAdapter { protected $object ; public function __construct () { $this -> object = new IndependentDeveloper2 (); } public function sum ( $a , $b ) { return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b ); } } // într-un singur loc creăm un adaptor concret și apoi folosim interfața $adapter1 = new ConcreteAdapter1 (); $adapter2 = nou ConcreteAdapter2 (); /** * Peste tot în cod nu folosim clase direct, dar prin interfață * această funcție nu contează ce clasă folosim, deoarece ne bazăm pe interfața * * @param IAdapter $adapter */ function sum ( IAdapter $ adaptor ) { echo $ adaptor -> suma ( 2 , 2 ); } suma ( $adapter1 ); suma ( $adapter2 );

PHP5.4

Exemplu în PHP 5.4 (trăsătură) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { public function anotherSum ( $a , $b ) { return $a + $b ; } } caracteristica TAdaptee { public function sum ( int $a , int $b ) { $metoda = $aceasta -> metoda ; returnează $acest -> $metodă ( $a , $b ); } } clasa SomeAdaptee extinde SomeClass { folosește TAdaptee ; private $method = 'someSum' ; } clasa AnotherAdaptee extinde AnotherClass { folosește TAdaptee ; private $method = 'otherSum' ; } $ uni = nou SomeAdaptee ; $altul = nou AnotherAdaptee ; $uni -> suma ( 2 , 2 ); $altul -> suma ( 5 , 2 );

PHP5.4 Compact

Exemplu în PHP 5.4 (Compact) <?php caracteristica TAdaptee { public function sum ( int $a , int $b ) { $metoda = $aceasta -> metoda ; returnează $acest -> $metodă ( $a , $b ); } } clasa SomeClass { folosește TAdaptee ; private $method = 'someSum' ; function public someSum ( $a , $b ) { return $a + $b ; } } clasa AnotherClass { folosește TAdaptee ; private $method = 'otherSum' ; function public anotherSum ( $a , $b ) { return $a + $b ; } } $ uni = nou SomeClass ; $altul = nou AnotherClass ; $uni -> suma ( 2 , 2 ); $altul -> suma ( 5 , 2 );

JavaScript

Exemplu JavaScript function Search ( text , word ) { var text = text ; var cuvânt = cuvânt ; aceasta . searchWordInText = function () { return text ; }; aceasta . getWord = function () { return word ; }; }; function SearchAdapter ( adaptat ) { this . searchWordInText = function () { return 'Aceste cuvinte' + adaptee . getWord () + ' găsit în text ' + adaptee . searchWordInText (); }; }; var căutare = căutare nouă ( „text” , „cuvinte” ); var searchAdapter = nou SearchAdapter ( căutare ); searchAdapter . searchWordInText ();

Python

Exemplu în Python clasa GameConsole : def create_game_picture ( self ): returnează „imagine din consolă” class Antena : def create_wave_picture ( self ): returnează „imagine din val” clasa SourceGameConsole ( GameConsole ): def get_picture ( self ): return self . create_game_picture () clasa SourceAntenna ( Antena ): def get_picture ( self ): return self . create_wave_picture () clasa TV : def __init__ ( self , source ): self . sursă = sursă def show_picture ( self ): return self . sursa . 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# - compoziție

Exemplu C# (compoziție) folosind System ; adaptor pentru spațiu de nume { class MainApp { static void Main () { // Creați adaptor și plasați o solicitare țintă țintă = adaptor nou (); tinta . cerere (); // Așteptați Consola utilizatorului . citește (); } } // „Țintă” class Target { public virtual void Solicitare () { Consola . WriteLine ( "Called TargetRequest()" ); } } // „Adaptor” class Adapter : Target { private Adaptee Adaptee = nou Adaptee (); public override void Request () { // Posibil să faceți o altă lucrare // și apoi apelați SpecificRequest adaptee . SpecificRequest (); } } // „Adaptat” class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Denumit SpecificRequest()" ); } } }

C# - moștenire

Exemplu C# (moștenire) folosind System ; adaptor pentru spațiu de nume { class MainApp { static void Main () { // Creați adaptor și plasați o cerere Adaptor Adaptor = adaptor nou (); adaptor . cerere (); // Așteptați Consola utilizatorului . citește (); } } // „Țintă” interfață ITarget { public void Request (); } // Puteți folosi clasa abstractă // „Adaptor” class Adapter : Adaptee , ITarget { public void Request () { // Posibil să faceți o altă lucrare // și apoi apelați SpecificRequest SpecificRequest (); } } // „Adaptat” class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Denumit SpecificRequest()" ); } } }

Delphi

exemplu Delphi adaptor de program; {$APPTYPE CONSOLE} {$R *.res} utilizări System.SysUtils; (*Interfața de utilizare a clientului din clasa TTarget realizată ca TAdapter*) (*TAdapter redirecționează apelul către TAdaptee*) tip TTarget = clasa functionRequest:string; virtual; Sfârşit; TAdapte = clasa funcția SpecificRequest:șir; Sfârşit; TAdapter = clasă (TTarget) fAdaptee: TAdaptee; functionRequest:string; trece peste; constructorCreate; Sfârşit; { TTarget } funcția TTarget.Request: șir; ÎNCEPE Rezultat:= 'Called Target Request()'; Sfârşit; {TAdaptee} funcția TAdaptee.SpecificRequest: șir; ÎNCEPE Rezultat:= 'Denumit SpecificRequest()'; Sfârşit; {TAdapter} constructor TAdapter.Create; ÎNCEPE fAdaptee:= TAdaptee.Create; Sfârşit; funcția TAdapter.Request: șir; ÎNCEPE (*E posibil să faceți o altă lucrare și când sunați SpecificRequest*) Rezultat:= fAdaptee.SpecificRequest; Sfârşit; var target: TTarget; ÎNCEPE încerca { TODO -oUser -cConsole Main : Inserați codul aici } (*creează un adaptor și plasează o cerere*) target:= TAdapter.Create; WriteLn(target.Request); WriteLn(#13#10+'Apăsați orice tastă pentru a continua...'); ReadLn; target.Free; cu exceptia pe E: Excepție nu Writeln(E.ClassName, ': ', E.Message); Sfârşit; Sfârşit.

Note

  1. Apropierea semnificațiilor termenilor shell și wrapper ( în engleză  wrapper - folosit ca sinonim pentru un decorator) duce uneori la confuzie și Adapter este definit ca sinonim pentru șablonul Decorator , în timp ce acestea sunt două șabloane diferite, iar acesta din urmă. rezolvă o altă sarcină și anume: conectarea obligațiilor suplimentare la obiect.
  2. Diferența este că modelul Fațadă este conceput pentru a simplifica interfața, în timp ce modelul Adaptor este conceput pentru a aduce diverse interfețe existente la același aspect dorit.
  3. În versiunile învechite ale limbajului PHP, accesul la SGBD este implementat ca un set de funcții, pentru fiecare SGBD au nume diferite și, uneori, un set diferit de parametri utilizați, ceea ce duce la probleme semnificative la trecerea de la un SGBD la altul, dacă o astfel de tranziție nu este furnizată în prealabil folosind șablonul Adaptor.

Literatură

  • Alan Shalloway, James R. Trott. Modele de design. O nouă abordare a designului orientat pe obiecte = Modelele de design explicate: O nouă perspectivă asupra designului orientat pe obiecte. - M . : „Williams” , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Tehnici de proiectare orientată pe obiecte. Design Patterns = Design Patterns: Elements of Reusable Object-Oriented Software. - Sankt Petersburg. : „Petru” , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (și ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Modele de design = Head First Design Patterns. - Sankt Petersburg. : Peter, 2011. - 656 p. - ISBN 978-5-459-00435-9 .

Link -uri