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
- 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.
- Beskriv klientgränssnittet genom vilket applikationsklasser kan använda tjänsteklassen.
- Skapa en adapterklass genom att implementera detta gränssnitt.
- 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.
- Implementera alla klientgränssnittsmetoder i adaptern. Adaptern måste delegera det mesta av arbetet till tjänsten.
- 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 på $ 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
- ↑ 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.
- ↑ 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.
- ↑ 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