Adapter (designmønster)

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 9. marts 2016; kontroller kræver 47 redigeringer .
Adapter
Adapter

Skabelonstrukturvisningsadapter
Type strukturel
Formål at organisere brugen af ​​funktionerne i et objekt, der ikke er tilgængeligt for ændring gennem en specielt oprettet grænseflade (bringer grænsefladen for en klasse (eller flere klasser) til grænsefladen af ​​den påkrævede type)
Gælder i sager systemet understøtter de nødvendige data og adfærd, men har en uhensigtsmæssig grænseflade. Den mest almindelige brug af Adapter-mønsteret er, når du vil oprette en klasse, der stammer fra en nyligt defineret eller allerede eksisterende abstrakt klasse.
fordele
  • indkapsling af implementeringen af ​​eksterne klasser (komponenter, biblioteker), systemet bliver uafhængigt af grænsefladen af ​​eksterne klasser;
  • overgangen til brugen af ​​andre eksterne klasser kræver ikke omarbejdelse af selve systemet, det er nok at implementere en klasse Adapter.
Relaterede skabeloner Facade , Dekoratør
Beskrevet i Design Patterns Ja

Adapter ( eng.  Adapter ) er et strukturelt designmønster, der er designet til at organisere brugen af ​​funktionerne i et objekt , som ikke er tilgængeligt for ændring gennem en specielt oprettet grænseflade . Med andre ord er det et strukturelt designmønster, der tillader objekter med inkompatible grænseflader at arbejde sammen.

Nøglefunktioner

Udfordring

Systemet understøtter de nødvendige data og adfærd, men har en uhensigtsmæssig grænseflade.

Løsning

Adapteren sørger for oprettelse af en indpakningsklasse [1] med den nødvendige grænseflade.

Medlemmer

En klasse Adapterkortlægger en klassegrænseflade Adapteetil en klassegrænseflade Target(som implementeres af klassen Adapter). Dette tillader objektet at Clientbruge objektet Adaptee(via adapteren Adapter), som om det var en forekomst af klassen Target.

Får således Clientadgang til grænsefladen Targetimplementeret af klassen Adapter, der omdirigerer opkaldet til Adaptee.

Konsekvenser

Adaptermønsteret gør det muligt at inkludere eksisterende objekter i nye objektstrukturer, uanset forskelle i deres grænseflader.

Noter og kommentarer

Adaptermønsteret gør det muligt for designprocessen at ignorere mulige forskelle i grænseflader af eksisterende klasser. Hvis der er en klasse, der har de nødvendige metoder og egenskaber (i det mindste konceptuelt), så kan du om nødvendigt altid bruge Adapter-mønsteret til at bringe dens grænseflade til den ønskede form.

Tæt på adapteren er facademønsteret , det er ikke altid muligt at skelne det ene fra det andet [2] .

Anvendelse af en skabelon

Et typisk eksempel på brug af Adapter-mønsteret er oprettelsen af ​​klasser, der fører til en enkelt grænseflade til en PHP -sprogfunktion, der giver adgang til forskellige DBMS [3] .

En løsning på dette problem ved hjælp af adapterskabelonen er vist i figuren.

Implementering

Inklusiv en allerede eksisterende klasse i en anden klasse. Grænsefladen for den omsluttende klasse opdateres for at opfylde de nye krav, og kald til dens metoder konverteres til kald til metoderne i den inkluderede klasse.


Implementeringstrin

  1. Sørg for, at du har to klasser med inkompatible grænseflader:
    • nyttig service - en hjælpeklasse, som du ikke kan ændre (det er enten tredjepart eller anden kode afhænger af det);
    • en eller flere klienter - eksisterende applikationsklasser, der er inkompatible med tjenesten på grund af en ubekvem eller uoverensstemmende grænseflade.
  2. Beskriv klientgrænsefladen, gennem hvilken applikationsklasser kunne bruge serviceklassen.
  3. Opret en adapterklasse ved at implementere denne grænseflade.
  4. Placer et felt i adapteren, der gemmer en reference til serviceobjektet. Typisk er dette felt udfyldt med objektet, der sendes til adapterens konstruktør. I tilfælde af simpel tilpasning kan dette objekt overføres som parametre til adaptermetoder.
  5. Implementer alle klientgrænseflademetoder i adapteren. Adapteren skal uddelegere det meste af arbejdet til tjenesten.
  6. Applikationen bør kun bruge adapteren gennem klientgrænsefladen. Dette vil gøre det nemt at skifte og tilføje adaptere i fremtiden.


Ruby

Eksempel i Ruby modul AdapterPattern # Tillader klienten at bruge Adaptees med inkompatible grænseflader via Adaptere med interface Target # Adaptee klasse Twitter def twit sætter 'Twit blev offentliggjort' til ende # Adaptee -klasse Facebook - def - indlæg sætter "Facebook-indlæg blev offentliggjort" til ende # Målmodul WebServiceInterface def send_message raise NotImplementedError end end # Adapterklasse TwitterAdapter inkluderer WebServiceInterface def initialize @webservice = Twitter . ny ende def send_message @webservice . tweet slutningen _ # Adapterklasse FacebookAdapter inkluderer WebServiceInterface def initialize @webservice = Facebook . ny ende def send_message @webservice . stolpe ende ende # Klientklasse Meddelelse attr_accessor :webservice def send @webservice . send_message end end def selv . kør sætter '=> Adapter' besked = Besked . ny besked . webservice = TwitterAdapter . ny besked . sende besked . webservice = FacebookAdapter . ny besked . sende sætter ' ' ende Adaptermønster . løb

Java - arv

Java- eksempel (via arv) // Target public interface Chief { public Object makeBreakfast (); offentligt objekt makeFrokost (); offentlige objekt lave middag (); } // Adaptee public class Plumber { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adapter public class ChiefAdapter udvider Blikkenslager implementerer Chef { 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 (); Objektfad = lm . _ laveMorgenmad (); spise ( fad ); fad = lm . laveFrokost (); spise ( fad ); fad = lm . lave middag (); spise ( fad ); ring til Ambulance (); } }

Java-sammensætning

Java- eksempel (via komposition) // Chief.java fil offentlig grænsefladechef { _ offentligt objekt laveMorgenmad (); offentlige objekt lave middag (); offentlig Objekt makeSupper (); } // Plumber.java fil offentlig klasse blikkenslager { public Object getPipe () { returner nyt objekt (); } public Object getKey () { returner nyt objekt (); } public Object getScrewDriver () { returner nyt objekt (); } } // ChiefAdapter.java fil public class ChiefAdapter implementerer Chief { privat Blikkenslager blikkenslager = ny Blikkenslager (); @Override public Object makeBreakfast () { returner blikkenslager . getkey (); } @Override public Object makeDinner () { returner blikkenslager . getScrewDriver (); } @Override public Object makeSupper () { returner blikkenslager . getPipe (); } } // Client.java fil public class Client { public static void main ( String [] args ) { Chief chief = new ChiefAdapter (); Objekttast = hoved . _ lave middag (); } }

scala

Scala eksempel pakkeobjektadapter { _ _ objekt Battlefield { protected var redTroops : Array [ Troop ] = Array () protected var blueTroops : Array [ Troop ] = Array () def addTroop ( troop : Troop ) : Enhed = { if ( troop . side == "red" ) { redTroops :+= troop } else if ( troop . side == "blue" ) { blueTroops :+= troop } else { smid ny undtagelse ( s"Ugyldig side ${ troop . side } for troop ${ troop . name } " ) } } def getClosestEnemyTroop ( side : String ): Troop = { if ( side == "red" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } private def getTroop ( tropper : Array [ Troop ]): Troop = { if ( tropper . length == 0 ) { throw new Exception ( "Ingen tilgængelige tropper" ) } tropper ( 0 ) } } klasse Troop ( val side : String , val navn : String , val tætVåben : String , val distanceVåben : String ) { def move ( retning : String , distance : Int ): Unit = { println ( s"Troop $ navn flytter $ retning $ distance yards" ) } def attack ( enemyTroop : Troop , attackType : String ) : Unit = { val weapon = attackType match { case "distance" => distanceWeapon case "close" => closeWeapon case _ => throw new Exception ( s"Ugyldig angrebstype $ attackType for troppe $ navn " ) } println ( s"Troop $ name angriber fjendens troop ${ enemyTroop . name } med deres ${ våben } s" ) } } egenskab LanceKnightTroopTrait { def moveForward ( afstand : Int ) : Enhed def attackClosest ( attackType : String ) : Unit } klasse LanceKnightTroop ( tilsidesætte val side : String , tilsidesætte val navn : String , tilsidesætte val closeWaben : String , tilsidesætte val distanceWeapon : String ) udvider Troop ( side , navn , closeWeapon , distanceWeapon ) med LanceKnightTroopTrait { tilsidesætte def moveForward ( distance : Int ): Enhed = { move ( "fremad" , distance ) } tilsidesætte def attackClosest ( attackType : String ): Unit = { attack ( Battlefield . getClosestEnemyTroop ( side ), attackType ) } } objekt AdapterTest udvider AbstractTest { tilsidesætte def run (): Enhed = { val troop = ny troop ( "blå" , "bueskytter" , "sværd" , "langbue" ) val lanceKnightTroop = ny LanceKnightTroop ( "rød" , "Lance Knights" , "gedde " , armbrøst ) Slagmark . addTroop ( troop ) Battlefield . addTroop ( lanceKnightTroop ) println ( "Output:" ) lanceKnightTroop . moveForward ( 300 ) lanceKnightTroop . attackClosest ( "tæt" ) } } } // Output: // Troop Lance Knights rykker frem på 300 yards // Troop Lance Knights angriber fjendens troppe Bueskytter med deres gedder

PHP5

Eksempel i PHP 5 <?php class IndependentDeveloper1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { public function nameIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } } interface IAdapter { public function sum ( $a , $b ); } klasse ConcreteAdapter1 implementerer IAdapter { protected $object ; offentlig funktion __construct () { $this -> object = new IndependentDeveloper1 (); } public function sum ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } klasse ConcreteAdapter2 implementerer IAdapter { protected $object ; offentlig funktion __construct () { $this -> object = new IndependentDeveloper2 (); } public function sum ( $a , $b ) { return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b ); } } //et sted opretter vi en konkret adapter og bruger derefter grænsefladen $adapter1 = new ConcreteAdapter1 (); $adapter2 = ny ConcreteAdapter2 (); /** * Overalt i koden bruger vi ikke klasser direkte, men gennem grænsefladen * denne funktion er ligegyldig hvilken klasse vi bruger, da vi er afhængige af grænsefladen * * @param IAdapter $adapter */ function sum ( IAdapter $ adapter ) { echo $ adapter -> sum ( 2 , 2 ); } sum ( $adapter1 ); sum ( $adapter2 );

PHP5.4

Eksempel i PHP 5.4 (egenskab) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { public function anotherSum ( $a , $b ) { return $a + $b ; } } egenskab TAdaptee { public function sum ( int $a , int $b ) { $metode = $this -> metode ; returner $dette -> $metode ( $a , $b ); } } class SomeAdaptee udvider SomeClass { use TAdaptee ; private $method = 'someSum' ; } class AnotherAdaptee udvider AnotherClass { brug TAdaptee ; privat $method = 'en andenSum' ; } $some = ny SomeAdaptee ; $another = ny AnotherAdaptee ; $nogle -> sum ( 2 , 2 ); $en anden -> sum ( 5 , 2 );

PHP5.4 Compact

Eksempel i PHP 5.4 (kompakt) <?php egenskab TAdaptee { public function sum ( int $a , int $b ) { $metode = $this -> metode ; returner $dette -> $metode ( $a , $b ); } } klasse SomeClass { brug TAdaptee ; private $method = 'someSum' ; public function someSum ( $a , $b ) { return $a + $b ; } } klasse AnotherClass { brug TAdaptee ; privat $method = 'en andenSum' ; public function anotherSum ( $a , $b ) { return $a + $b ; } } $some = ny SomeClass ; $another = ny AnotherClass ; $nogle -> sum ( 2 , 2 ); $en anden -> sum ( 5 , 2 );

JavaScript

JavaScript eksempel funktion Søg ( tekst , ord ) { var tekst = tekst ; var ord = ord ; dette . searchWordInText = function () { return text ; }; dette . getWord = function () { return word ; }; }; funktion Søgeadapter ( tilpasset ) { denne . searchWordInText = function () { return 'Disse ord' + adaptee . getWord () + ' fundet i tekst ' + adaptee . searchWordInText (); }; }; var søgning = ny søgning ( "tekst" , "ord" ); var searchAdapter = ny søgeadapter ( søgning ); søgeadapter . searchWordInText ();

Python

Eksempel i Python klasse GameConsole : def create_game_picture ( selv ): returner 'billede fra konsol' klasse Antenne : def create_wave_picture ( selv ): returner 'billede fra wave' klasse SourceGameConsole ( GameConsole ): def get_picture ( selv ): returner selv . create_game_picture () klasse KildeAntenne ( Antenne ): def get_picture ( selv ): returner selv . create_wave_picture () klasse TV : def __init__ ( selv , kilde ): selv . source = source def show_picture ( selv ): returner selv . kilde . få_billede () g = KildeGameConsole () a = KildeAntenne () game_tv = TV ( g ) cabel_tv = TV ( a ) print ( game_tv . show_picture ()) print ( cabel_tv . show_picture ())

C# - sammensætning

C# -eksempel (sammensætning) bruger System ; navneområdeadapter { _ class MainApp { static void Main () { // Opret adapter og placer en anmodning Target target = new Adapter (); mål . anmodning (); // Vent på brugerkonsollen . læs (); } } // "Mål" klasse Target { public virtual void Request () { Console . WriteLine ( "Called TargetRequest()" ); } } // "Adapter" klasse Adapter : Target { private Adaptee adaptee = new Adaptee (); public override void Request () { // Gør eventuelt noget andet arbejde // og kald derefter SpecificRequest adaptee . SpecificRequest (); } } // "Adaptee" klasse Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

C# - arv

C# -eksempel (arv) bruger System ; navneområdeadapter { _ klasse MainApp { static void Main () { // Opret adapter og placer en anmodning Adapter adapter = ny Adapter (); adapter . anmodning (); // Vent på brugerkonsollen . læs (); } } // "Mål" interface ITarget { public void Request (); } // Du kan bruge abstrakt klasse // "Adapter" klasse Adapter : Adaptee , ITarget { public void Request () { // Gør eventuelt noget andet arbejde // og kald derefter SpecificRequest SpecificRequest (); } } // "Adaptee" klasse Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

Delphi

Delphi eksempel program adapter; {$APPTYPE KONSOL} {$R *.res} bruger System.SysUtils; (*Klientbrugsgrænseflade af klasse TTarget realiseret som TAdapter*) (*TAdapter omdirigerer opkaldet til TAdaptee*) type TTarget = klasse functionRequest:streng; virtuelle; ende; TAapte = klasse funktion SpecificRequest:streng; ende; TAdapter = klasse(TTarget) fAdaptee: TAdaptee; functionRequest:streng; tilsidesætte; constructorCreate; ende; { TTarget } funktion TTarget.Request: streng; begynde Result:= 'Called Target Request()'; ende; {TAdaptee} funktion TAdaptee.SpecificRequest: streng; begynde Result:= 'Called SpecificRequest()'; ende; {TAadapter} konstruktør TAdapter.Create; begynde fAdaptee:= TAdaptee.Create; ende; funktion TAdapter.Request: streng; begynde (*Gør eventuelt noget andet arbejde, og når du ringer SpecificRequest*) Resultat:= fAdaptee.SpecificRequest; ende; var target: TTarget; begynde prøve { TODO -oUser -cConsole Main : Indsæt kode her } (*opret adapter og indsend en anmodning*) target:= TAdapter.Create; WriteLn(target.Request); WriteLn(#13#10+'Tryk på en vilkårlig tast for at fortsætte...'); ReadLn; mål.Gratis; undtagen på E: Undtagelse do Writeln(E.ClassName, ': ', E.Message); ende; ende.

Noter

  1. Nærheden af ​​betydningerne af begreberne shell og wrapper ( engelsk  wrapper - brugt som et synonym for en dekoratør) fører nogle gange til forvirring, og Adapteren er defineret som et synonym for Decorator skabelonen , mens disse er to forskellige skabeloner og sidstnævnte løser en anden opgave, nemlig: at forbinde yderligere forpligtelser til at gøre indsigelse.
  2. Forskellen er, at facademønsteret er designet til at forenkle grænsefladen, mens adaptermønsteret er designet til at bringe forskellige eksisterende grænseflader til det samme ønskede udseende.
  3. I forældede versioner af PHP-sproget er adgangen til DBMS implementeret som et sæt funktioner, for hver DBMS har de forskellige navne og nogle gange et andet sæt parametre, hvilket fører til betydelige problemer ved skift fra et DBMS til en anden, hvis en sådan overgang ikke leveres på forhånd ved hjælp af adapterskabelonen.

Litteratur

  • Alan Shalloway, James R. Trott. Design mønstre. En ny tilgang til objektorienteret design = Designmønstre forklaret: Et nyt perspektiv på objektorienteret design. - M . : "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Teknikker til objektorienteret design. Designmønstre = Designmønstre: Elementer af genanvendelig objektorienteret software. - Sankt Petersborg. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (også ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Designmønstre = Head First Design Patterns. - Sankt Petersborg. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .

Links