Sovitin (suunnittelukuvio)

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 9. maaliskuuta 2016 tarkistetusta versiosta . tarkastukset vaativat 47 muokkausta .
Sovitin
Sovitin

Mallin rakennenäkymäsovitin
Tyyppi rakenteellinen
Tarkoitus järjestää sellaisen objektin toimintojen käyttö, joka ei ole muokattavissa erityisesti luodun käyttöliittymän kautta (tuo luokan (tai useamman luokan) rajapinnan vaaditun tyyppiseen käyttöliittymään)
Pätee tapauksissa järjestelmä tukee vaadittuja tietoja ja käyttäytymistä, mutta sillä on sopimaton käyttöliittymä. Yleisin Adapter-mallin käyttö on silloin, kun halutaan luoda luokka, joka on peräisin juuri määritellystä tai jo olemassa olevasta abstraktista luokasta.
Plussat
  • ulkoisten luokkien (komponenttien, kirjastojen) toteutuksen kapselointi, järjestelmästä tulee riippumaton ulkoisten luokkien rajapinnasta;
  • siirtyminen muiden ulkoisten luokkien käyttöön ei vaadi itse järjestelmän uudelleenkäsittelyä, riittää yhden luokan toteuttaminen Adapter.
Aiheeseen liittyvät mallit Julkisivu , sisustaja
Kuvattu suunnittelukuvioissa Joo

Adapteri ( eng.  Adapter ) on rakennesuunnittelumalli , joka on suunniteltu organisoimaan kohteen toimintojen käyttö, jota ei voi muokata erityisesti luodun käyttöliittymän kautta . Toisin sanoen se on rakennesuunnittelumalli, jonka avulla objektit, joilla on yhteensopimattomat rajapinnat, voivat toimia yhdessä.

Tärkeimmät ominaisuudet

Haaste

Järjestelmä tukee vaadittuja tietoja ja käyttäytymistä, mutta siinä on sopimaton käyttöliittymä.

Ratkaisu

Sovitin mahdollistaa kääreluokan [1] luomisen vaaditulla liitännällä.

Jäsenet

Luokka Adapterkartoittaa luokkarajapinnan Adapteeluokkaliittymään Target(jonka luokka toteuttaa Adapter). Tämä sallii objektin Clientkäyttää objektia Adaptee(sovittimen kautta Adapter) ikään kuin se olisi luokan esiintymä Target.

Siten käyttää luokan toteuttamaa Clientkäyttöliittymää , joka ohjaa kutsun osoitteeseen . TargetAdapterAdaptee

Seuraukset

Sovitinmalli mahdollistaa olemassa olevien objektien sisällyttämisen uusiin objektirakenteisiin riippumatta niiden rajapintojen eroista.

Huomautuksia ja kommentteja

Sovitinmallin avulla suunnitteluprosessi voi jättää huomioimatta mahdolliset erot olemassa olevien luokkien rajapinnoissa. Jos on olemassa luokka, jolla on vaaditut menetelmät ja ominaisuudet (ainakin käsitteellisesti), niin tarvittaessa voit aina käyttää Adapter-mallia saadakseen sen rajapinnan haluttuun muotoon.

Sovittimen lähellä on julkisivukuvio , jota ei aina ole mahdollista erottaa toisistaan ​​[2] .

Mallin käyttäminen

Tyypillinen esimerkki Adapter-mallin käytöstä on luokkien luominen, jotka johtavat yhteen PHP -kielifunktion käyttöliittymään, joka tarjoaa pääsyn erilaisiin tietokantajärjestelmiin [3] .

Ratkaisu tähän ongelmaan käyttämällä sovitinmallia on esitetty kuvassa.

Toteutus

Jo olemassa olevan luokan sisällyttäminen toisella luokalla. Sisältävän luokan käyttöliittymä päivitetään vastaamaan uusia vaatimuksia ja sen menetelmien kutsut muunnetaan kutsuiksi sisällytetyn luokan menetelmille.


Käyttöönoton vaiheet

  1. Varmista, että sinulla on kaksi luokkaa, joiden liitännät eivät ole yhteensopivia:
    • hyödyllinen palvelu - hyödyllisyysluokka, jota et voi muuttaa (se on joko kolmannen osapuolen tai muu koodi riippuu siitä);
    • yksi tai useampi asiakas - olemassa olevat sovellusluokat, jotka eivät ole yhteensopivia palvelun kanssa hankalan tai yhteensopimattoman käyttöliittymän vuoksi.
  2. Kuvaa asiakasliittymä, jonka kautta sovellusluokat voivat käyttää palveluluokkaa.
  3. Luo sovitinluokka toteuttamalla tämä käyttöliittymä.
  4. Aseta sovittimeen kenttä, joka tallentaa viittauksen palveluobjektiin. Yleensä tämä kenttä täytetään sovittimen rakentajalle välitetyllä objektilla. Yksinkertaisen mukautuksen tapauksessa tämä objekti voidaan välittää parametreina sovitinmenetelmille.
  5. Toteuta kaikki asiakasliittymämenetelmät sovittimessa. Sovittimen on delegoitava suurin osa työstä palvelulle.
  6. Sovelluksen tulisi käyttää sovitinta vain asiakasliittymän kautta. Tämä helpottaa sovittimien vaihtamista ja lisäämistä tulevaisuudessa.


Ruby

Esimerkki Rubyssa moduuli AdapterPattern # Sallii asiakkaan käyttää sovittimia yhteensopimattomien liitäntöjen kanssa sovittimien kautta, joissa on käyttöliittymä Kohde # Adaptee luokka Twitter def twit laittaa " Twit julkaistiin" loppuun # Sopeutuva luokka Facebook def post laittaa "Facebook- viesti julkaistiin" loppuun # Kohdemoduuli WebServiceInterface def send_message nosta NotImplementedError end end # Sovitinluokka TwitterAdapter sisältää WebServiceInterfacen def initialize @webservice = Twitter . uusi loppu def send_message @webservice . twiitin loppu _ # Adapteriluokka FacebookAdapter sisältää WebServiceInterfacen def initialize @webservice = Facebook . uusi loppu def send_message @webservice . post loppu loppu # Asiakasluokan Viesti attr_accessor : webservice def send @webservice . send_message end end itsevarmasti . _ run laittaa '=> sovittimen' viesti = Viesti . Uusi viestiä . verkkopalvelu = TwitterAdapter . uusi viesti . lähettää viestiä . verkkopalvelu = FacebookAdapter . uusi viesti . lähettää laittaa ' ' lopun Adapter Pattern . juosta

Java - periytyminen

Java - esimerkki (perinnön kautta) // Kohde julkinen käyttöliittymä Päällikkö { public Object makeBreakfast (); julkinen Object makeLunch (); julkinen Object makeDinner (); } // Adaptee public class Putkimies { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adapter public class ChiefAdapter laajenee Putkimies toteuttaa Päällikkö { public Object makeBreakfast () { return getGasket (); } public Object makeLunch () { return getPipe (); } public Object makeDinner () { return getScrewNut (); } } // Client public class Asiakas { public static void eat ( Object dish ) { ... } public static void main ( String [] args ) { Chief ch = new ChiefAdapter (); Objektilautanen = ch . _ teeAamiainen (); syödä ( ruokalaji ); ruokalaji = ch . teeLounas (); syödä ( ruokalaji ); ruokalaji = ch . teeDinner (); syödä ( ruokalaji ); soita ambulanssiin (); } }

Java-kokoonpano

Java - esimerkki (koostumuksen kautta) // Chief.java-tiedosto julkisen käyttöliittymän päällikkö { julkinen Object makeBreakfast (); julkinen Object makeDinner (); julkinen Object makeSupper (); } // Putkimies.java-tiedosto julkisen luokan putkimies { public Object getPipe () { return new Object (); } public Object getKey () { return new Object (); } public Object getScrewDriver () { return new Object (); } } // ChiefAdapter.java-tiedosto public class ChiefAdapter toteuttaa Chief { yksityinen Putkimies putkimies = uusi Putkimies (); @Override public Object makeBreakfast () { paluu putkimies . getkey (); } @Override public Object makeDinner () { paluu putkimies . getScrewDriver (); } @Override public Object makeSupper () { return putkimies . getPipe (); } } // Client.java-tiedosto public class Asiakas { public static void main ( String [] args ) { Chief chief = new ChiefAdapter (); Objektiavain = pää . _ teeDinner (); } }

scala

Scala esimerkki pakettiobjektisovitin { _ _ esine Battlefield { suojattu var redTroops : Array [ Joukko ] = Array ( ) suojattu var blueTroops : Array [ Joukko ] = Array ( ) def addTroop ( joukko : Joukko ) : Yksikkö = { if ( joukko . puoli == "punainen" ) { redJoukkoja :+= joukko } else if ( joukko . puoli == "sininen" ) { blueTroops :+= joukko } else { heittää uusi poikkeus ( s"Virheellinen puoli ${ troop . side } for troop ${ troop . name } " ) } } def getClosestEnemyTroop ( puoli : String ): Joukko = { if ( puoli == "punainen" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } yksityinen def getTroop ( joukot : Array [ Joukko ]): Joukko = { if ( joukot . pituus == 0 ) { heittää uusi poikkeus ( "Ei käytettävissä olevia joukkoja" ) } joukot ( 0 ) } } luokka Joukko ( val side : String , val nimi : String , val closeAse : String , val distanceWeapon : String ) { def move ( suunta : merkkijono , etäisyys : int ): Yksikkö = { println ( s"Joukun $ nimi liikkuu $ suunnassa $ etäisyys jaardia " ) } def attack ( enemyTroop : Troop , attackType : String ) : Yksikkö = { val ase = attackType match { case "etäisyys" => etäisyysAsetapaus " close " => closeAsetapaus _ => heittää uusi Poikkeus ( s"Virheellinen hyökkäystyyppi $ attackType joukolle $ nimi " ) } println ( s"Joukkojen $ nimi hyökkää vihollisjoukkoja ${ enemyTroop . name } vastaan ​​${ ase } s" ) } } ominaisuus LanceKnightTroopTrait { def moveForward ( etäisyys : Int ) : Yksikkö def attackClosest ( attackType : String ) : Yksikkö } luokka LanceKnightTroop ( ohita val side : String , ohita val nimi : String , ohita val closeWeapon : String , ohita val distanceWeapon : String ) laajentaa joukkoa ( puoli , nimi , closeWeapon , distanceWeapon ) kanssa LanceKnightTroopTrait { override def moveForward ( etäisyys : Int ): Yksikkö = { liikkua ( "eteenpäin" , etäisyys ) } ohittaa def attackClosest ( attackType : String ): Yksikkö = { hyökkäys ( Battlefield . getClosestEnemyTroop ( side ), attackType ) } } object AdapterTest expands AbstractTest { ohittaa def run (): Yksikkö = { val troop = uusi joukko ( "sininen" , "jousimiehet" , "miekka" , "pitkäjousi" ) val lanceKnightTroop = uusi LanceKnightTroop ( "punainen" , "Lance Knights" , "hauki" " , varsijousi ) Taistelukenttä . addTroop ( joukko ) Battlefield . addTroop ( lanceKnightTroop ) println ( "Output:" ) lanceKnightTroop . Siirry eteenpäin ( 300 ) lanceKnightTroop . attackClosest ( "sulje" ) } } } // Tulos: // Joukko Lance Knights liikkuu eteenpäin 300 jaardia // Troop Lance Knights hyökkää vihollisjoukkojen jousimiesten kimppuun haukeineen

PHP5

Esimerkki PHP 5 :ssä <?php class IndependentDeveloper1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { julkisen funktion nimiIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } } käyttöliittymä IAdapter { julkinen funktio summa ( $a , $b ); } luokka ConcreteAdapter1 toteuttaa IAAdapterin { suojattu $objekti ; public function __construct () { $this -> object = new IndependentDeveloper1 (); } julkinen funktio summa ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } luokka ConcreteAdapter2 toteuttaa IAAdapterin { suojattu $objekti ; public function __construct () { $this -> object = new IndependentDeveloper2 (); } julkinen funktio summa ( $a , $b ) { return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b ); } } //yhdessä paikassa luomme betonisovittimen ja käytämme sitten käyttöliittymää $adapter1 = new ConcreteAdapter1 (); $adapteri2 = uusi ConcreteAdapter2 (); /** * Kaikkialla koodissa emme käytä luokkia suoraan, vaan käyttöliittymän kautta * tällä funktiolla ei ole väliä mitä luokkaa käytämme, koska luotamme käyttöliittymään * * @param IAdapter $adapter */ funktion summa ( IAdapter $ sovitin ) { kaiku $ sovitin -> summa ( 2 , 2 ); } summa ( $adapteri1 ); summa ( $sovitin2 );

PHP5.4

Esimerkki PHP 5.4:ssä (Trait) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class AnotherClass { julkinen funktio otherSum ( $a , $b ) { return $a + $b ; } } ominaisuus TAdaptee { julkinen funktio summa ( int $a , int $b ) { $method = $this -> method ; palauttaa $this -> $method ( $a , $b ); } } class SomeAdaptee laajentaa SomeClass { use TAdaptee ; yksityinen $method = 'someSum' ; } class AnotherAdaptee laajentaa AnotherClass { use TAdaptee ; yksityinen $method = 'toinenSumma' ; } $joku = uusi SomeAdaptee ; $toinen = uusi AnotherAdaptee ; $joku -> summa ( 2 , 2 ); $toinen -> summa ( 5 , 2 );

PHP5.4 Compact

Esimerkki PHP 5.4:ssä (Compact) <?php ominaisuus TAdaptee { julkinen funktio summa ( int $a , int $b ) { $method = $this -> method ; palauttaa $this -> $method ( $a , $b ); } } class SomeClass { käytä TAdaptee ; yksityinen $method = 'someSum' ; julkinen funktio jokinSumma ( $a , $b ) { return $a + $b ; } } class AnotherClass { käytä TAdaptee ; yksityinen $method = 'toinenSumma' ; julkinen funktio otherSum ( $a , $b ) { return $a + $b ; } } $joku = uusi SomeClass ; $toinen = uusi AnotherClass ; $joku -> summa ( 2 , 2 ); $toinen -> summa ( 5 , 2 );

JavaScript

JavaScript esimerkki function Haku ( teksti , sana ) { var teksti = teksti ; var sana = sana ; tämä . searchWordInText = function () { return text ; }; tämä . getWord = function ( ) { paluusana ; }; }; function SearchAdapter ( adaptee ) { this . searchWordInText = function () { return 'Nämä sanat' + adaptee . getWord () + ' löytyy tekstistä ' + adaptee . searchWordInText (); }; }; var search = new Haku ( "teksti" , "sanat" ); var searchAdapter = uusi SearchAdapter ( haku ); hakusovitin . searchWordInText ();

Python

Esimerkki Pythonissa luokka GameConsole : def create_game_picture ( itse ): palauttaa 'kuva konsolista' luokan antenni : def create_wave_picture ( self ): return 'kuva aallosta' luokka SourceGameConsole ( GameConsole ): def get_picture ( self ): return self . create_game_picture () luokka SourceAntenna ( Antenna ): def get_picture ( self ): return self . luo_aaltokuva () luokka TV : def __init__ ( itse , lähde ): itse . lähde = lähde def show_picture ( self ): return self . lähde . hanki_kuva () g = SourceGameConsole () a = SourceAntenna () game_tv = TV ( g ) cabel_tv = TV ( a ) tulosta ( game_tv . show_picture ()) tulosta ( cabel_tv . show_picture ())

C# - kokoonpano

C# -esimerkki (koostumus) käyttäen System ; nimiavaruussovitin { _ class MainApp { static void Main () { // Luo sovitin ja aseta pyyntö Kohdekohde = uusi sovitin ( ); kohde . pyytää (); // Odota käyttäjän konsolia . lue (); } } // "Kohde" class Kohde { public virtual void Pyyntö () { Konsoli . WriteLine ( "Called TargetRequest()" ); } } // "Sovitin" class Sovitin : Kohde { yksityinen sopeutuja sopeutuja = uusi sopeutuja (); public override void Request () { // Tee mahdollisesti muuta työtä // ja soita sitten SpecificRequest adaptee . SpecificRequest (); } } // "Sopeutunut" class Adaptee { public void SpecificRequest () { Konsoli . WriteLine ( "Called SpecificRequest()" ); } } }

C# - perintö

C# -esimerkki (perintö) käyttäen System ; nimiavaruussovitin { _ class MainApp { static void Main () { // Luo sovitin ja aseta pyyntö Sovitinsovitin = uusi Sovitin (); sovitin . pyytää (); // Odota käyttäjän konsolia . lue (); } } // "Kohde" käyttöliittymä ITarget { public void Request (); } // Voit käyttää abstraktia luokkaa // "Sovitin" class Sovitin : Adaptee , ITarget { public void Request () { // Tee mahdollisesti muuta työtä // ja kutsu sitten SpecificRequest SpecificRequest (); } } // "Sopeutunut" class Adaptee { public void SpecificRequest () { Konsoli . WriteLine ( "Called SpecificRequest()" ); } } }

Delphi

Delphi esimerkki ohjelma-adapteri; {$APPTYPE CONSOLE} {$R *.res} käyttää System.SysUtils; (*TTarget-luokan asiakaskäyttöliittymä toteutettu TAadapterina*) (*TAdapter uudelleenohjaa puhelun TAdaptee*) tyyppi TTarget = luokka functionRequest:string; virtuaalinen; loppu; TAdapte = luokka toiminto SpecificRequest:string; loppu; TAsovitin = luokka (TTkohde) fAdaptee: TAdaptee; functionRequest:string; ohittaa; rakentajaLuo; loppu; { TTarget } toiminto TTarget.Request: merkkijono; alkaa Result:= 'Called Target Request()'; loppu; {TAdaptee} toiminto TAdaptee.SpecificRequest: merkkijono; alkaa Result:= 'Called SpecificRequest()'; loppu; {TAsovitin} rakentaja TAdapter.Create; alkaa fAdaptee:= TAdaptee.Create; loppu; toiminto TAdapter.Request: merkkijono; alkaa (*Mahdollisesti tehdä muita töitä ja soita SpecificRequest*) Tulos:= fAdaptee.SpecificRequest; loppu; var target: TTarget; alkaa yrittää { TODO -oUser -cConsole Main : Lisää koodi tähän } (*luo sovitin ja tee pyyntö*) kohde:= TAadapter.Create; WriteLn(target.Request); WriteLn(#13#10+'Jatka painamalla mitä tahansa näppäintä...'); ReadLn; kohde.Ilmainen; paitsi E: Poikkeus Writeln(E.Luokannimi, ':', E.Viesti); loppu; loppu.

Muistiinpanot

  1. Termien kuori ja kääre ( englanniksi  wrapper - käytetty synonyyminä sisustajalle) läheisyys johtaa joskus sekaannukseen ja Adapteri määritellään synonyymiksi sisustaja -mallille , kun taas nämä ovat kaksi eri mallia ja jälkimmäinen. ratkaisee eri tehtävän, nimittäin: lisävelvoitteiden liittäminen objektiin.
  2. Erona on, että julkisivukuvio on suunniteltu yksinkertaistamaan käyttöliittymää, kun taas Adapter-kuvio on suunniteltu tuomaan useat olemassa olevat rajapinnat samaan haluttuun ilmeeseen.
  3. PHP-kielen vanhentuneissa versioissa pääsy DBMS-järjestelmään on toteutettu funktioiden sarjana, jokaiselle DBMS:lle niillä on eri nimet ja joskus eri parametrijoukko, mikä johtaa merkittäviin ongelmiin vaihdettaessa yhdestä DBMS:stä toiseen. toinen, jos tällaista siirtymää ei tarjota etukäteen käyttämällä sovitinmallia.

Kirjallisuus

  • Alan Shalloway, James R. Trott. Suunnittelumalleja. Uusi lähestymistapa olio-suuntautuneeseen suunnitteluun = Design Patterns Explained: A New Perspective on Object-Oriented Design. - M . : "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Olio-suunnittelun tekniikat. Suunnittelumallit = Suunnittelumallit: Uudelleenkäytettävän olio-ohjelmiston elementit. - Pietari. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (myös ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Suunnittelukuviot = Head First Design Patterns. - Pietari. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .

Linkit