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
- 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.
- Beskriv klientgrænsefladen, gennem hvilken applikationsklasser kunne bruge serviceklassen.
- Opret en adapterklasse ved at implementere denne grænseflade.
- 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.
- Implementer alle klientgrænseflademetoder i adapteren. Adapteren skal uddelegere det meste af arbejdet til tjenesten.
- 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 på $ 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
- ↑ 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.
- ↑ 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.
- ↑ 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