Adaptér (designový vzor)
Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od
verze recenzované 9. března 2016; kontroly vyžadují
47 úprav .
Adaptér |
---|
Adaptér |
Adaptér zobrazení struktury šablony |
Typ |
strukturální |
Účel |
organizovat používání funkcí objektu, který není k dispozici pro úpravu, prostřednictvím speciálně vytvořeného rozhraní (přenese rozhraní třídy (nebo několika tříd) na rozhraní požadovaného typu) |
Platí v případech |
systém podporuje požadovaná data a chování, ale má nevhodné rozhraní. Nejběžnější použití vzoru Adaptér je, když chcete vytvořit třídu, která je odvozena z nově definované nebo již existující abstraktní třídy. |
profesionálové |
- zapouzdření implementace externích tříd (komponent, knihoven), systém se stává nezávislým na rozhraní externích tříd;
- přechod na použití jiných externích tříd nevyžaduje přepracování samotného systému, stačí implementovat jednu třídu Adapter.
|
Související šablony |
Fasáda , dekoratér |
Popsáno v Návrhové vzory |
Ano |
Adaptér ( anglicky Adapter ) je strukturní návrhový vzor navržený k organizaci použití funkcí objektu , který není dostupný pro modifikaci prostřednictvím speciálně vytvořeného rozhraní . Jinými slovy, je to strukturální návrhový vzor, který umožňuje objektům s nekompatibilními rozhraními spolupracovat.
Klíčové vlastnosti
Výzva
Systém podporuje požadovaná data a chování, ale má nevhodné rozhraní.
Řešení
Adaptér umožňuje vytvoření obalové třídy [1] s požadovaným rozhraním.
Členové
Třída Adaptermapuje rozhraní třídy Adapteena rozhraní třídy Target(které je implementováno třídou Adapter). To umožňuje objektu Clientpoužívat objekt Adaptee(prostřednictvím adaptéru Adapter), jako by to byla instance třídy Target.
Přistupuje tedy Clientk rozhraní Targetimplementovanému třídou Adapter, která přesměruje volání na Adaptee.
Důsledky
Vzor Adaptér umožňuje zahrnutí existujících objektů do nových objektových struktur bez ohledu na rozdíly v jejich rozhraních.
Poznámky a komentáře
Vzor Adaptér umožňuje procesu návrhu ignorovat možné rozdíly v rozhraních existujících tříd. Pokud existuje třída, která má požadované metody a vlastnosti (alespoň koncepčně), pak v případě potřeby můžete vždy pomocí vzoru Adapter uvést její rozhraní do požadované podoby.
V blízkosti Adaptéru je vzor Fasáda , není vždy možné jeden od druhého odlišit [2] .
Použití šablony
Typickým příkladem použití vzoru Adapter je vytváření tříd, které vedou k jedinému rozhraní funkce jazyka PHP , které poskytuje přístup k různým DBMS [3] .
Řešení tohoto problému pomocí šablony Adapter je znázorněno na obrázku.
Implementace
Zahrnutí již existující třídy do jiné třídy. Rozhraní obklopující třídy je aktualizováno, aby vyhovovalo novým požadavkům, a volání jejích metod se převádí na volání metod zahrnuté třídy.
Kroky implementace
- Ujistěte se, že máte dvě třídy s nekompatibilními rozhraními:
- užitečná služba - třída utility, kterou nemůžete změnit (je to buď kód třetí strany, nebo na ní závisí jiný kód);
- jeden nebo více klientů – existující třídy aplikací, které jsou nekompatibilní se službou kvůli nepohodlnému nebo neodpovídajícímu rozhraní.
- Popište klientské rozhraní, jehož prostřednictvím by třídy aplikací mohly používat třídu služeb.
- Vytvořte třídu adaptéru implementací tohoto rozhraní.
- Umístěte do adaptéru pole, které bude ukládat odkaz na objekt služby. Toto pole je obvykle vyplněno objektem předaným konstruktoru adaptéru. V případě jednoduché adaptace lze tento objekt předat jako parametry metodám adaptéru.
- Implementujte všechny metody klientského rozhraní v adaptéru. Adaptér musí delegovat většinu práce na službu.
- Aplikace by měla používat adaptér pouze prostřednictvím klientského rozhraní. Díky tomu bude v budoucnu snadné měnit a přidávat adaptéry.
Ruby
Příklad v
Ruby
modul AdapterPattern
# Umožňuje klientovi používat Adaptéry s nekompatibilními rozhraními prostřednictvím Adaptérů s rozhraním Cíl
# Adaptee
class Twitter
def twit
udává konec 'Twit byl publikován
'
# Adaptee
class Facebook
def post
uvádí 'Facebook příspěvek byl publikován
' konec
# Cílový
modul WebServiceInterface
def send_message
raise NotImplementedError
end
end
# Adaptér
třídy TwitterAdapter
zahrnuje WebServiceInterface
def inicializovat
@webservice = Twitter . nový
konec
def send_message
@webservice . konec tweetu
_
# Adaptér
třídy FacebookAdapter
obsahuje WebServiceInterface
def inicializovat
@webservice = Facebook . nový
konec
def send_message
@webservice . příspěvek
konec
konec
#
Třída klienta Zpráva
attr_accessor :webservice
def poslat
@webservice . send_message
end
end
def self . spustit
vloží '=> Adaptér'
zpráva = Zpráva . Nový
zpráva . webservice = TwitterAdapter . nová
zpráva . poslat
zpráva . webová služba = FacebookAdapter . nová
zpráva . poslat
ukončí ' '
konec
Vzor adaptéru . běh
Java - dědičnost
Příklad
Java (prostřednictvím dědičnosti)
// Cílové
veřejné rozhraní Chief
{
public Object makeBreakfast ();
public Object makeLunch ();
public Object makeDinner ();
}
// Adaptee
public class Instalatér
{
public Object getScrewNut ()
{ ... }
public Object getPipe ()
{ ... }
public Object getGasket ()
{ ... }
}
// Adaptér
public class ChiefAdapter extends Instalatér implementuje Chief
{
public Object makeBreakfast ()
{
return getGasket ();
}
public Object makeLunch ()
{
return getPipe ();
}
public Object makeDinner ()
{
return getScrewNut ();
}
}
//
Public class klienta Klient
{
public static void eat ( Object dish )
{ ... }
public static void main ( String [] args )
{
Chief ch = new ChiefAdapter ();
Objektová mísa = ch . udělatSnídaně ();
jíst ( jídlo );
miska = ch . makeLunch ();
jíst ( jídlo );
miska = ch . makeDinner ();
jíst ( jídlo );
volejte Ambulance ();
}
}
Java složení
Příklad
Java (přes složení)
// Soubor Chief.java
public interface Chief {
public Object makeSnídaně ();
public Object makeDinner ();
public Object makeSupper ();
}
// Soubor Plumber.java
public class Instalatér {
public Object getPipe () {
return new Object ();
}
public Object getKey () {
return new Object ();
}
public Object getScrewDriver () {
return new Object ();
}
}
// Soubor ChiefAdapter.java
public class ChiefAdapter implementuje Chief {
soukromý Instalatér instalatér = nový Instalatér ();
@Override
public Object makeBreakfast () {
return instalatér . getkey ();
}
@Override
public Object makeDinner () {
return instalatér . getScrewDriver ();
}
@Override
public Object makeSupper () {
return instalatér . getPipe ();
}
}
// Soubor Client.java
public class klient {
public static void main ( String [] args ) {
Hlavní šéf = nový hlavní adaptér ();
Klíč objektu = hlava . makeDinner ();
}
}
scala
Příklad
Scala
package object adapter {
objekt Battlefield {
protected var redTroops : Array [ Vojsko ] = Array ()
chráněná var blueTroops : Array [ Vojsko ] = Array ()
def addTroop ( jednotka : Vojsko ) : Jednotka = {
if ( jednotka . strana == "červená" ) {
červená Vojska :+= jednotka
} else if ( jednotka . strana == "modrá" ) {
modrá Jednotka :+= jednotka
} else {
zahoď novou výjimku ( s"Neplatná strana ${ jednotka . strana } pro jednotku ${ jednotka . jméno } " )
}
}
def getClosestEnemyTroop ( strana : String ): Vojsko = {
if ( strana == "červená" ) {
getTroop ( blueTroops )
} else {
getTroop ( redTroops )
}
}
private def getTroop ( jednotky : Array [ Vojsko ]): Vojsko = {
if ( jednotky . délka == 0 ) {
hod novou výjimku ( "Žádné dostupné jednotky" )
}
jednotky ( 0 )
}
}
class Vojsko (
strana valu : String , jméno valu : String , val closeZbraň : String , val distanceZbraň : String ) {
def move ( direction : String , distance : Int ): Unit = {
println ( s" Jméno jednotky $ se pohybuje $ směrem na $ vzdálenost yardů" ) }
def attack ( nepřítelská jednotka : Vojsko , typ útoku : Řetězec ) : Jednotka = {
val zbraň = typ útoku shoda {
případ "vzdálenost" => vzdálenost
Pouzdro na zbraň "zavřít" => zavřít
pouzdro na zbraň _ => hodit novou výjimku ( s"Neplatný typ útoku $ typ útoku pro oddíl $ name " )
}
println ( s" Vojka $ name útočí na nepřátelskou jednotku ${ nepřátelská jednotka . name } svými ${ zbraní } s" )
}
}
rys LanceKnightTroopTrait {
def moveForward ( distance : Int ) : Unit
def útok Nejbližší ( typ útoku : Řetězec ) : Jednotka
}
class LanceKnightTroop (
přepsat stranu valu : String , přepsat val name : String , přepsat val closeZbraň : String , přepsat val distanceWeapon : String ) rozšiřuje oddíl ( strana , jméno , zavřítZbraň , vzdálenostZbraň ) o LanceKnightTroopTrait {
override def moveForward ( distance : Int ): Unit = {
move ( "forward" , distance )
}
override def attackClosest ( attackType : String ): Unit = {
attack ( Battlefield . getClosestEnemyTroop ( side ), attackType )
}
}
object AdapterTest rozšiřuje AbstractTest {
override def run (): Unit = {
val troop = new Troop ( "modrá" , "Lukostřelci" , "meč" , "dlouhý luk" )
val lanceKnightTroop = new LanceKnightTroop ( "red" , "Lance Knights" , "pike " , kuše )
Bojiště . addTroop ( vojsko )
Battlefield . addTroop ( lanceKnightTroop )
println ( "Výstup:" )
lanceKnightTroop . moveForward ( 300 )
lanceKnightTroop . attackClosest ( "close" )
}
}
}
// Výstup:
// Vojsko Lance Knights se pohybuje vpřed o 300 yardů
// Vojsko Lance Knights útočí svými štikami na nepřátelské jednotky Archers
PHP5
Příklad v
PHP 5
<?php
class IndependentDeveloper1
{
public function calc ( $a , $b ) {
return $a + $b ;
}
}
class IndependentDeveloper2
{
jméno veřejné funkceIsVeryLongAndUncomfortable ( $a , $b ) { return $a + $b ; } }
interface IAdapter
{
public function sum ( $a , $b );
}
class ConcreteAdapter1 implementuje IAdapter
{
protected $object ;
public function __construct () {
$this -> objekt = new IndependentDeveloper1 ();
}
public function sum ( $a , $b ) {
return $this -> object -> calc ( $a , $b );
}
}
class ConcreteAdapter2 implementuje IAdapter
{
protected $object ;
public function __construct () {
$this -> objekt = new IndependentDeveloper2 ();
}
public function sum ( $a , $b ) {
return $this -> object -> nameIsVeryLongAndUncomfortable ( $a , $b );
}
}
//na jednom místě vytvoříme konkrétní adaptér a poté použijeme rozhraní
$adapter1 = new ConcreteAdapter1 ();
$adapter2 = new ConcreteAdapter2 ();
/**
* Všude v kódu nepoužíváme třídy přímo, ale přes rozhraní
* této funkci nezáleží na tom, kterou třídu použijeme, protože se spoléháme na rozhraní
*
* @param IAdapter $adapter
*/
function sum ( IAdapter $ adapter ) {
echo $ adapter -> sum ( 2 , 2 );
}
součet ( $adapter1 );
součet ( $adapter2 );
PHP5.4
Příklad v
PHP 5.4 (vlastnost)
<?php
class SomeClass
{
public function someSum ( $a , $b )
{
return $a + $b ;
}
}
class JinýTřída
{
veřejná funkce jinýSoučet ( $a , $b )
{
return $a + $b ;
}
}
vlastnost TAdaptee
{
public function sum ( int $a , int $b )
{
$method = $this -> metoda ;
return $this -> $metoda ( $a , $b );
}
}
class SomeAdaptee rozšiřuje SomeClass
{
use TAdaptee ;
private $method = 'nějakýSoučet' ;
}
class AnotherAdaptee rozšiřuje AnotherClass
{
use TAdaptee ;
private $method = 'jinýSoučet' ;
}
$some = new SomeAdaptee ;
$další = nový JinýPřizpůsobený ;
$nějaké -> součet ( 2 , 2 );
$další -> součet ( 5 , 2 );
PHP5.4 Compact
Příklad v
PHP 5.4 (Compact)
<?php
vlastnost TAdaptee
{
public function sum ( int $a , int $b )
{
$method = $this -> metoda ;
return $this -> $metoda ( $a , $b );
}
}
class SomeClass
{
use TAdaptee ;
private $method = 'nějakýSoučet' ;
public function someSum ( $a , $b )
{
return $a + $b ;
}
}
class AnotherClass
{
use TAdaptee ;
private $method = 'jinýSoučet' ;
veřejná funkce jinýSoučet ( $a , $b )
{
return $a + $b ;
}
}
$some = new SomeClass ;
$dalsi = novy DalsiClass ;
$nějaké -> součet ( 2 , 2 );
$další -> součet ( 5 , 2 );
JavaScript
Příklad
JavaScriptu
function Hledat ( text , slovo ) {
var text = text ;
var slovo = slovo ;
toto . searchWordInText = function () {
return text ;
};
toto . getWord = function () {
return word ;
};
};
function SearchAdapter ( adaptee ) {
this . searchWordInText = function () {
return 'Tato slova' + adaptee . getWord ()
+ ' nalezené v textu ' + adaptee . searchWordInText ();
};
};
var search = new Search ( "text" , "slova" );
var searchAdapter = new SearchAdapter ( hledat );
searchAdapter . searchWordInText ();
Python
Příklad v
Pythonu
class GameConsole :
def create_game_picture ( self ):
return 'picture from console'
class Antenna :
def create_wave_picture ( self ):
return 'picture from wave'
class SourceGameConsole ( GameConsole ):
def get_picture ( self ):
return self . create_game_picture ()
class SourceAntenna ( Antenna ):
def get_picture ( self ):
return self . create_wave_picture ()
class TV :
def __init__ ( self , zdroj ):
self . source = source
def show_picture ( self ):
return self . zdroj . 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# - složení
Příklad
C# (složení)
pomocí System ;
adaptér
jmenného prostoru {
class MainApp
{
static void Main ()
{
// Vytvoření adaptéru a zadání požadavku
Cílový cíl = nový adaptér ();
cíl . žádost ();
// Počkejte na uživatelskou
konzoli . číst ();
}
}
// "Cílová"
class Target
{
public virtual void Request ()
{
Console . WriteLine ( "Called TargetRequest()" );
}
}
// "Adaptér"
class Adapter : Target
{
private Adaptee adaptee = new Adaptee ();
public override void Request ()
{
// Možná proveďte nějakou jinou práci
// a pak zavolejte SpecificRequest
adaptee . SpecificRequest ();
}
}
// "Adaptee"
class Adaptee
{
public void SpecificRequest ()
{
Console . WriteLine ( "Called SpecificRequest()" );
}
}
}
C# - dědičnost
Příklad
C# (dědičnost)
pomocí System ;
adaptér
jmenného prostoru {
class MainApp
{
static void Main ()
{
// Vytvoření adaptéru a zadání požadavku
Adaptér adaptér = new Adapter ();
adaptér . žádost ();
// Počkejte na uživatelskou
konzoli . číst ();
}
}
// "Cílová"
interface ITarget
{
public void Request ();
}
// Můžete použít abstraktní třídu
// "Adaptér"
class Adapter : Adaptee , ITarget
{
public void Request ()
{
// Možná udělat nějakou jinou práci
// a pak zavolat SpecificRequest
SpecificRequest ();
}
}
// "Adaptee"
class Adaptee
{
public void SpecificRequest ()
{
Console . WriteLine ( "Called SpecificRequest()" );
}
}
}
Delphi
Příklad
Delphi
programový adaptér;
{$APPTYPE KONZOLE}
{$R *.res}
používá
System.SysUtils;
(*Rozhraní pro použití klienta třídy TTarget realizované jako TAdapter*)
(*TAdapter přesměruje volání na TAdaptee*)
typ
TTarget = třída
functionRequest:string; virtuální;
konec;
TAdapte = třída
funkce SpecificRequest:string;
konec;
TAdapter = class(TTarget)
fAdaptee: TAdaptee;
functionRequest:string; přepsat;
konstruktorCreate;
konec;
{ TTarget }
funkce TTarget.Request: string;
začít
Result:= 'Called Target Request()';
konec;
{TAdaptee}
funkce TAdaptee.SpecificRequest: řetězec;
začít
Result:= 'Called SpecificRequest()';
konec;
{TAdapter}
konstruktor TAdapter.Create;
začít
fAdaptee:= TAdaptee.Create;
konec;
function TAdapter.Request: string;
začít
(*Případně udělat nějakou jinou práci a když zavolejte SpecificRequest*)
Result:= fAdaptee.SpecificRequest;
konec;
var target: TTarget;
začít
Snaž se
{ TODO -oUser -cConsole Main : Sem vložte kód}
(*vytvořit adaptér a zadat požadavek*)
target:= TAdapter.Create;
WriteLn(target.Request);
WriteLn(#13#10+'Pokračujte stisknutím libovolné klávesy...');
ReadLn;
target.Free;
až na
na E: Výjimka do
Writeln(E.ClassName, ': ', E.Message);
konec;
konec.
Poznámky
- ↑ Blízkost významů pojmů shell a wrapper ( anglicky wrapper - používá se jako synonymum pro dekoratér) někdy vede k nejasnostem a Adapter je definován jako synonymum pro šablonu Decorator , přičemž se jedná o dvě různé šablony a druhá jmenovaná řeší jiný úkol, a to: připojení dalších povinností k objektu.
- ↑ Rozdíl je v tom, že vzor Fasáda je navržen tak, aby zjednodušil rozhraní, zatímco vzor Adaptér je navržen tak, aby přinesl různým existujícím rozhraním stejný požadovaný vzhled.
- ↑ V zastaralých verzích jazyka PHP je přístup do DBMS implementován jako sada funkcí, pro každý DBMS mají jiné názvy a někdy i jinou sadu použitých parametrů, což vede k výrazným problémům při přechodu z jednoho DBMS na jiný, pokud takový přechod není zajištěn předem pomocí šablony Adaptér.
Literatura
- Alan Shalloway, James R. Trott. Designové vzory. Nový přístup k objektově orientovanému navrhování = vysvětlení návrhových vzorů: Nový pohled na objektově orientovaný design. - M .: "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
- E. Gamma, R. Helm, R. Johnson, J. Vlissides . Techniky objektově orientovaného navrhování. Design Patterns = Design Patterns: Prvky opakovaně použitelného objektově orientovaného softwaru. - Petrohrad. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (také ISBN 5-272-00355-1 )
- Eric Freeman, Elizabeth Freeman. Design Patterns = Návrhové vzory Head First. - Petrohrad. : Peter, 2011. - 656 s. - ISBN 978-5-459-00435-9 .
Odkazy