Adapter (designmönster)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 9 mars 2016; kontroller kräver 47 redigeringar .
Adapter
Adapter

Mall Structure View Adapter
Sorts strukturell
Ändamål att organisera användningen av funktionerna för ett objekt som inte är tillgängligt för modifiering genom ett speciellt skapat gränssnitt (tar gränssnittet för en klass (eller flera klasser) till gränssnittet av den önskade typen)
Gäller i ärenden systemet stöder nödvändiga data och beteenden, men har ett olämpligt gränssnitt. Den vanligaste användningen av adaptermönstret är när du vill skapa en klass som härrör från en nydefinierad eller redan existerande abstrakt klass.
fördelar
  • inkapsling av implementeringen av externa klasser (komponenter, bibliotek), systemet blir oberoende av gränssnittet för externa klasser;
  • övergången till användning av andra externa klasser kräver inte omarbetning av själva systemet, det räcker med att implementera en klass Adapter.
Relaterade mallar Fasad , dekoratör
Beskrivs i Design Patterns Ja

Adapter ( eng.  Adapter ) är ett strukturellt designmönster utformat för att organisera användningen av funktionerna i ett objekt som inte är tillgängligt för modifiering genom ett speciellt skapat gränssnitt . Med andra ord är det ett strukturellt designmönster som gör att objekt med inkompatibla gränssnitt kan arbeta tillsammans.

Nyckelfunktioner

Utmana

Systemet stöder nödvändig data och beteende, men har ett olämpligt gränssnitt.

Lösning

Adaptern möjliggör skapandet av en omslagsklass [1] med det erforderliga gränssnittet.

Medlemmar

En klass Adaptermappar ett klassgränssnitt Adapteetill ett klassgränssnitt Target(som implementeras av klassen Adapter). Detta tillåter objektet att Clientanvända objektet Adaptee(via adaptern Adapter) som om det vore en instans av klassen Target.

Åtkomst Clienttill gränssnittet som Targetimplementeras av klassen Adaptersom omdirigerar anropet till Adaptee.

Konsekvenser

Adaptermönstret tillåter att befintliga objekt inkluderas i nya objektstrukturer, oavsett skillnader i deras gränssnitt.

Anteckningar och kommentarer

Adaptermönstret tillåter designprocessen att ignorera möjliga skillnader i gränssnitten för befintliga klasser. Om det finns en klass som har de metoder och egenskaper som krävs (åtminstone begreppsmässigt), kan du vid behov alltid använda adaptermönstret för att få dess gränssnitt till önskad form.

Nära adaptern finns fasadmönstret , det är inte alltid möjligt att skilja det ena från det andra [2] .

Använda en mall

Ett typiskt exempel på att använda adaptermönstret är skapandet av klasser som leder till ett enda gränssnitt för en PHP -språkfunktion som ger tillgång till olika DBMS [3] .

En lösning på detta problem med hjälp av adaptermallen visas i figuren.

Implementering

Inkluderar en redan befintlig klass i en annan klass. Gränssnittet för den omslutande klassen uppdateras för att möta de nya kraven, och anrop till dess metoder konverteras till anrop till metoderna för den inkluderade klassen.


Implementeringssteg

  1. Se till att du har två klasser med inkompatibla gränssnitt:
    • användbar tjänst - en verktygsklass som du inte kan ändra (det är antingen tredje part eller annan kod beror på det);
    • en eller flera klienter - befintliga applikationsklasser som är inkompatibla med tjänsten på grund av ett obekvämt eller felaktigt gränssnitt.
  2. Beskriv klientgränssnittet genom vilket applikationsklasser kan använda tjänsteklassen.
  3. Skapa en adapterklass genom att implementera detta gränssnitt.
  4. Placera ett fält i adaptern som kommer att lagra en referens till serviceobjektet. Vanligtvis fylls det här fältet med objektet som skickas till adapterns konstruktor. Vid enkel anpassning kan detta objekt skickas som parametrar till adaptermetoder.
  5. Implementera alla klientgränssnittsmetoder i adaptern. Adaptern måste delegera det mesta av arbetet till tjänsten.
  6. Applikationen bör endast använda adaptern via klientgränssnittet. Detta kommer att göra det enkelt att byta och lägga till adaptrar i framtiden.


Ruby

Exempel i Ruby modul AdapterPattern # Tillåter klienten att använda Adaptees med inkompatibla gränssnitt via adaptrar med gränssnitt Target # Adaptee klass Twitter def twit sätter " Twit publicerades" slutet # Anpassad klass Facebook - def - inlägg sätter slutet på "Facebook-inlägget publicerades" . # Målmodul WebServiceInterface def send_message raise NotImplementedError end end # Adapterklass TwitterAdapter inkluderar WebServiceInterface def initiera @webservice = Twitter . nytt slut def send_message @webservice . tweet slut slut # Adapterklass FacebookAdapter inkluderar WebServiceInterface def initialisera @webservice = Facebook . nytt slut def send_message @webservice . stolpeände _ _ # Klientklass Meddelande attr_accessor :webservice skicka def @webservice . send_message end end def själv . kör sätter '=> Adapter' meddelande = Meddelande . ny meddelande . webbtjänst = TwitterAdapter . nytt meddelande . skicka meddelande . webbtjänst = FacebookAdapter . nytt meddelande . skicka sätter ' ' slutslut Adaptermönster . springa

Java - arv

Java- exempel (via arv) // Target public interface Chief { public Object makeBreakfast (); public Object makeLunch (); public Object makeDinner (); } // Adaptee public class Plumber { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adapter public class ChiefAdapter extends Plumber implements 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 maträtt ) { ... } public static void main ( String [] args ) { Chief ch = new ChiefAdapter (); Objektfat = lm . _ laga frukost (); äta ( maträtt ); maträtt = lm . makeLunch (); äta ( maträtt ); maträtt = lm . laga middag (); äta ( maträtt ); ring Ambulans (); } }

Java-komposition

Java- exempel (via komposition) // Chief.java-fil chef för offentligt gränssnitt { offentligt objekt makeFrukost (); public Object makeDinner (); offentligt objekt makeSupper (); } // Plumber.java filen offentlig klass Rörmokare { public Object getPipe () { returnera nytt objekt (); } public Object getKey () { return new Object (); } public Object getScrewDriver () { returnera nytt objekt (); } } // ChiefAdapter.java fil public class ChiefAdapter implementerar Chief { privat Rörmokare rörmokare = ny Rörmokare (); @Override public Object makeBreakfast () { return plumber . getkey (); } @Override public Object makeDinner () { return plumber . getScrewDriver (); } @Åsidosätt offentligt objekt makeSupper () { return plumber . getPipe (); } } // Client.java-filen public class Client { public static void main ( String [] args ) { Chief chief = new ChiefAdapter (); Objektnyckel = huvud . _ laga middag (); } }

scala

Scala exempel paketobjektadapter { _ _ objekt Battlefield { protected var redTroops : Array [ Troop ] = Array () protected var blueTroops : Array [ Troop ] = Array () def addTroop ( trupp : Trupp ) : Enhet = { if ( trupp . sida == " röd " ) { redTroops :+= trupp } annat if ( trupp . sida == "blå" ) { blueTroops :+= trupp } else { kasta nytt undantag ( s"Ogiltig sida ${ trupp . sida } för trupp ${ trupp . namn } " ) } } def getClosestEnemyTroop ( sida : String ): Troop = { if ( sida == "red" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } privat def getTroop ( trupper : Array [ Trupp ]): Trupp = { if ( trupper . längd == 0 ) { kasta nytt undantag ( "Inga tillgängliga trupper" ) } trupper ( 0 ) } } klass Trupp ( val sida : String , val namn : String , val closeWeapon : String , val distansVapen : String ) { def move ( riktning : String , distans : Int ): Enhet = { println ( s "Trupp $ namn flyttar $ riktning $ avstånd yards" ) } def attack ( enemyTroop : Troop , attackType : String ) : Unit = { val weapon = attackType match { case "distance" => distanceWeapon case "close" => closeWeapon case _ => kasta nytt Undantag ( s" Ogiltig attacktyp $ attackType för trupp $ namn " ) } println ( s"Trupp $ name attackerar fiendetrupp ${ enemyTroop . name } med deras ${ vapen } s" ) } } egenskap LanceKnightTroopTrait { def moveForward ( avstånd : Int ) : Enhet def attackClosest ( attackType : String ) : Unit } klass LanceKnightTroop ( åsidosätt val sida : String , åsidosätta val namn : String , åsidosätta val closeWeapon : String , åsidosätta val distansVapen : String ) utökar Troop ( sida , namn , closeWeapon , distansWeapon ) med LanceKnightTroopTrait { åsidosätt def moveForward ( avstånd : Int ): Enhet = { flytta ( "framåt" , avstånd ) } åsidosätt def attackClosest ( attackType : String ): Enhet = { attack ( Battlefield . getClosestEnemyTroop ( sida ), attackType ) } } objekt AdapterTest utökar AbstractTest { åsidosätt def körning (): Enhet = { val trupp = ny trupp ( "blå" , "bågskyttar" , "svärd" , "långbåge" ) val lanceKnightTroop = ny LanceKnightTroop ( "röd" , "Lance Knights" , "gädda " , armborst ) Slagfält . addTroop ( trupp ) Battlefield . addTroop ( lanceKnightTroop ) println ( "Output:" ) lanceKnightTroop . moveForward ( 300 ) lanceKnightTroop . attackNärmast ( "stäng" ) } } } // Output: // Troop Lance Knights går framåt på 300 yards // Troop Lance Knights attackerar fiendens trupp Archers med sina gäddor

PHP5

Exempel i PHP 5 <?php class IndependentDeveloper1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { public function nameIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } } gränssnitt IAdapter { public function summa ( $a , $b ); } klass ConcreteAdapter1 implementerar IAdapter { protected $object ; public function __construct () { $this -> object = new IndependentDeveloper1 (); } public function summa ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } class ConcreteAdapter2 implementerar IAdapter { protected $object ; public function __construct () { $this -> object = new IndependentDeveloper2 (); } public function summa ( $a , $b ) { return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b ); } } //på ett ställe skapar vi en konkret adapter och använder sedan gränssnittet $adapter1 = new ConcreteAdapter1 (); $adapter2 = new ConcreteAdapter2 (); /** * Överallt i koden använder vi inte klasser direkt, men genom gränssnittet * spelar denna funktion ingen roll vilken klass vi använder, eftersom vi förlitar oss på gränssnittet * * @param IAdapter $adapter */ function summa ( IAdapter $ adapter ) { echo $ adapter -> summa ( 2 , 2 ); } summa ( $adapter1 ); summa ( $adapter2 );

PHP5.4

Exempel i PHP 5.4 (egenskap) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { public function anotherSum ( $a , $b ) { return $a + $b ; } } egenskap TAdaptee { public function summa ( int $a , int $b ) { $method = $this -> method ; returnera $this -> $metod ( $a , $b ); } } class SomeAdaptee utökar SomeClass { use TAdaptee ; privat $method = 'someSum' ; } class AnotherAdaptee utökar AnotherClass { use TAdaptee ; privat $method = 'annanSumma' ; } $some = ny SomeAdaptee ; $another = ny AnotherAdaptee ; $some -> summa ( 2 , 2 ); $annan -> summa ( 5 , 2 );

PHP5.4 Compact

Exempel i PHP 5.4 (kompakt) <?php egenskap TAdaptee { public function summa ( int $a , int $b ) { $method = $this -> method ; returnera $this -> $metod ( $a , $b ); } } class SomeClass { använd TAdaptee ; privat $method = 'someSum' ; public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { använd TAdaptee ; privat $method = 'annanSumma' ; public function anotherSum ( $a , $b ) { return $a + $b ; } } $some = ny SomeClass ; $another = ny AnotherClass ; $some -> summa ( 2 , 2 ); $annan -> summa ( 5 , 2 );

JavaScript

JavaScript- exempel function Sök ( text , ord ) { var text = text ; var ord = ord ; detta . searchWordInText = function () { return text ; }; detta . getWord = function ( ) { returord ; }; }; function SearchAdapter ( adaptee ) { detta . searchWordInText = function () { return 'Dessa ord' + adaptee . getWord () + ' finns i text ' + adaptee . searchWordInText (); }; }; var sök = ny sökning ( "text" , "ord" ); var searchAdapter = new SearchAdapter ( sök ); sökadapter . searchWordInText ();

Python

Exempel i Python class GameConsole : def create_game_picture ( själv ): returnera 'bild från konsol' klass Antenn : def create_wave_picture ( själv ): returnera 'bild från våg' klass SourceGameConsole ( GameConsole ): def get_picture ( self ): returnera själv . skapa_spelsbild () class SourceAntenna ( Antenna ): def get_picture ( self ): returnera själv . create_wave_picture () klass TV : def __init__ ( själv , källa ): själv . source = source def show_picture ( self ): returnera själv . källa . 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# - sammansättning

C# -exempel (komposition) använder System ; namnutrymmesadapter { _ class MainApp { static void Main () { // Skapa adapter och placera en begäran Target target = new Adapter (); mål . begäran (); // Vänta på användarkonsolen . läs (); } } // "Mål" class Target { public virtual void Request () { Console . WriteLine ( "Called TargetRequest()" ); } } // "Adapter" class Adapter : Target { private Adaptee adaptee = new Adaptee (); public override void Request () { // Gör eventuellt något annat arbete // och ring sedan SpecificRequest adaptee . SpecificRequest (); } } // "Adaptee" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

C# - arv

C# -exempel (arv) använder System ; namnutrymmesadapter { _ class MainApp { static void Main () { // Skapa adapter och placera en begäran Adapteradapter = ny Adapter (); adapter . begäran (); // Vänta på användarkonsolen . läs (); } } // "Mål" gränssnitt ITarget { public void Request (); } // Du kan använda abstrakt klass // "Adapter" class Adapter : Adaptee , ITarget { public void Request () { // Gör eventuellt något annat arbete // och anrop SpecificRequest SpecificRequest (); } } // "Adaptee" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Called SpecificRequest()" ); } } }

Delphi

Delphi exempel programadapter; {$APPTYPE KONSOL} {$R *.res} använder System.SysUtils; (*Kundanvändningsgränssnitt för klass TTarget realiserat som TAdapter*) (*TAdapter omdirigerar samtalet till TAdaptee*) typ TTarget = klass functionRequest:sträng; virtuell; slutet; TAapte = klass function SpecificRequest:string; slutet; TAdapter = klass(TTarget) fAdaptee: TAdaptee; functionRequest:sträng; åsidosätta; constructorCreate; slutet; { TTarget } funktion TTarget.Request: sträng; Börja Result:= 'Called Target Request()'; slutet; {TAadaptee} funktion TAdaptee.SpecificRequest: sträng; Börja Result:= 'Called SpecificRequest()'; slutet; {TAdapter} konstruktör TAdapter.Create; Börja fAdaptee:= TAdaptee.Create; slutet; funktion TAdapter.Request: sträng; Börja (*Möjligen göra något annat arbete och när du ringer SpecificRequest*) Resultat:= fAdaptee.SpecificRequest; slutet; var target: TTarget; Börja Prova { TODO -oUser -cConsole Main : Infoga kod här } (*skapa adapter och skicka en förfrågan*) target:= TAdapter.Create; WriteLn(target.Request); WriteLn(#13#10+'Tryck på valfri tangent för att fortsätta...'); ReadLn; target.Free; bortsett från på E: Undantag gör Writeln(E.ClassName, ': ', E.Message); slutet; slutet.

Anteckningar

  1. Närheten till betydelserna av begreppen skal och omslag ( engelska  wrapper - används som synonym för en dekoratör) leder ibland till förvirring och Adaptern definieras som en synonym för dekoratörsmallen , medan dessa är två olika mallar och den senare löser en annan uppgift, nämligen: koppla ytterligare skyldigheter till invändning.
  2. Skillnaden är att fasadmönstret är designat för att förenkla gränssnittet, medan adaptermönstret är designat för att få olika befintliga gränssnitt till samma önskade utseende.
  3. I föråldrade versioner av PHP-språket implementeras åtkomst till DBMS som en uppsättning funktioner, för varje DBMS har de olika namn och ibland en annan uppsättning parametrar som används, vilket leder till betydande problem när man byter från ett DBMS till en annan, om en sådan övergång inte tillhandahålls i förväg med hjälp av adaptermallen.

Litteratur

  • Alan Shalloway, James R. Trott. Design mönster. Ett nytt tillvägagångssätt för objektorienterad design = Designmönster förklaras: Ett nytt perspektiv på objektorienterad design. - M . : "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Tekniker för objektorienterad design. Designmönster = Designmönster: Element av återanvändbar objektorienterad programvara. - St Petersburg. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (även ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Designmönster = Head First Design Patterns. - St Petersburg. : Peter, 2011. - 656 sid. - ISBN 978-5-459-00435-9 .

Länkar