Most (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í 11 úprav .
Most
Most
Typ strukturální
Popsáno v Návrhové vzory Ano

Mostní vzor je strukturální návrhový  vzor používaný v softwarovém návrhu k „oddělení abstrakce a implementace , aby se mohly nezávisle měnit“. Vzor mostu používá zapouzdření , agregaci a může používat dědičnost za účelem sdílení odpovědností mezi třídami.

Účel

Když se třída často mění, výhody objektově orientovaného přístupu se stanou velmi užitečnými, což vám umožní provádět změny v programu s minimální znalostí implementace programu. Vzor mostu je užitečný tam, kde se často mění nejen samotná třída, ale také to, co dělá.

Popis

Když jsou abstrakce a implementace odděleny, mohou se nezávisle měnit. Jinými slovy, když je implementována prostřednictvím vzoru mostu, změna struktury rozhraní nezasahuje do změny struktury implementace. Zvažte takovou abstrakci jako postavu. Existuje mnoho typů tvarů, z nichž každý má své vlastní vlastnosti a metody. Existuje však něco, co všechny postavy spojuje. Každý tvar musí být například schopen kreslit sám sebe, měřítko atd. Kreslení grafiky se přitom může lišit v závislosti na typu OS nebo grafické knihovny. Tvary musí být schopny kreslit samy sebe v různých grafických prostředích, ale je nepraktické implementovat všechny metody kreslení v každém tvaru nebo upravovat tvar pokaždé, když se metoda kreslení změní. V tomto případě pomáhá vzor mostu, který umožňuje vytvářet nové třídy, které budou implementovat kreslení v různých grafických prostředích. Pomocí tohoto přístupu je velmi snadné přidávat nové tvary i způsoby jejich kreslení.

Spojení znázorněné šipkou ve schématech může mít 2 významy: a) "druh" v souladu s principem Liskovovy substituce ab) jeden z možných implementací abstrakce. Jazyky obvykle používají dědičnost k implementaci a) i b), což má tendenci nafukovat hierarchie tříd.

Most slouží právě k vyřešení tohoto problému: objekty jsou vytvářeny ve dvojicích z objektu třídy hierarchie A a hierarchie B, dědičnost v rámci hierarchie A má podle Liskova význam „varianta“ a pro koncept „ implementace abstrakce“ je použit odkaz z objektu A na jeho spárovaný objekt B.

Použití

Architektura Java AWT je zcela založena na tomto vzoru - hierarchie java.awt.xxx pro úchyty a sun.awt.xxx pro implementace.

Příklady

Příklad C++

Zdrojový text v C++ #include <iostream> pomocí jmenného prostoru std ; třída zásuvka { veřejnost : virtuální void drawCircle ( int x , int y , int poloměr ) = 0 ; }; class SmallCircleDrawer : public Drawer { veřejnost : const double radiusMultiplier = 0,25 ; void drawCircle ( int x , int y , int poloměr ) přepíše { cout << "Malý střed kruhu " << x << ", " << y << " poloměr = " << radius * radiusMultiplier << endl ; } }; class LargeCircleDrawer : public Drawer { veřejnost : const double radiusMultiplier = 10 ; void drawCircle ( int x , int y , int poloměr ) přepíše { cout << "Velký střed kruhu " << x << ", " << y << " poloměr = " << radius * radiusMultiplier << endl ; } }; třída Tvar { chráněno : Zásuvka * zásuvka ; veřejnost : Tvar ( zásuvka * drw ) { šuplík = drw ; } tvar () {} virtuální void draw () = 0 ; virtuální void zvětšitRadius ( int multiplikátor ) = 0 ; }; class Circle : public Shape { int x , y , poloměr ; veřejnost : Kruh ( int _x , int _y , int _radius , zásuvka * drw ) { šuplík = drw ; setX ( _x ); setY ( _y ); setRadius ( _radius ); } void draw () override { šuplík -> drawCircle ( x , y , poloměr ); } void zvětšit Poloměr ( int multiplikátor ) override { poloměr *= násobitel ; } void setX ( int_x ) { _ x = _x ; } void setY ( int_y ) { _ y = _y _ } void setRadius ( int _radius ) { poloměr = _poloměr ; } }; int main ( int argc , char * argv []) { Tvar * tvary [ 2 ] = { new Circle ( 5 , 10 , 10 , new LargeCircleDrawer ()), nový kruh ( 20 , 30 , 100 , nový SmallCircleDrawer ())}; for ( int i = 0 ; i < 2 ; i ++ ) { tvary [ i ] -> kreslit (); } návrat 0 ; } // Výstup Střed velkého kruhu = 5 , 10 poloměr = 100 Střed malého kruhu = 20 , poloměr 30 = 25,0

Příklad Java

Zdroj Java veřejné rozhraní Zásuvka { public void drawCircle ( int x , int y , int poloměr ); } public class SmallCircleDrawer implementuje Drawer { public static final double radiusMultiplier = 0,25 ; @Override public void drawCircle ( int x , int y , int radius ) { System . ven . println ( "střed malého kruhu = " + x + "," + y + " poloměr = " + poloměr * násobič poloměru ); } } public class LargeCircleDrawer implementuje Drawer { public static final int polomerMultiplikator = 10 ; @Override public void drawCircle ( int x , int y , int radius ) { System . ven . println ( "Velký střed kruhu = " + x + "," + y + " poloměr = " + poloměr * poloměrNásobitel ); } } public abstract class Shape { chráněná zásuvka ; _ chráněný tvar ( zásuvka ) { tento . šuplík = šuplík ; } veřejný abstrakt void draw (); veřejný abstrakt void zvětšitRadius ( int multiplikátor ); } public class Kruh rozšiřuje tvar { private int x ; soukromé int y ; private int poloměr ; public Circle ( int x , int y , int poloměr , Zásuvka zásuvka ) { super ( zásuvka ); setX ( x ); setY ( y ); setRadius ( poloměr ); } @Override public void draw () { drawer . drawCircle ( x , y , poloměr ); } @Override public void zvětšit Poloměr ( int multiplikátor ) { poloměr *= multiplikátor ; } public int getX () { return x ; } public int getY () { return y ; } public int getRadius () { return polomer ; } public void setX ( int x ) { this . x = x ; } public void setY ( int y ) { this . y = y _ } public void setRadius ( int radius ) { this . poloměr = poloměr ; } } // Třída ukazující, jak funguje návrhový vzor "Bridge". public class Aplikace { public static void main ( String [] args ){ Tvar [] tvary = { new Circle ( 5 , 10 , 10 , new LargeCircleDrawer ()), new Circle ( 20 , 30 , 100 , new SmallCircleDrawer ())}; for ( Tvar další : tvary ) další . kreslit (); } } // Výstup Střed velkého kruhu = 5 , 10 poloměr = 100 Střed malého kruhu = 20 , 30 poloměr = 25,0

Příklad v C#

Zdrojový text v C# pomocí System ; jmenný prostor most { // Testovací aplikace MainApp class MainApp { static void Main () { Abstraction ab = new RefinedAbstraction (); // Nastaví implementaci a zavolá ab . Implementor = new ConcreteImplementorA (); ab _ operace (); // Změna implementace a volání ab . Implementor = new ConcreteImplementorB (); ab _ operace (); // Počkejte na uživatelskou konzoli . číst (); } } /// <summary> /// Abstrakce - abstrakce /// </summary> /// <remarks> /// <li> /// <lu>definuje rozhraní abstrakce;</lu> /// < lu >ukládá odkaz na objekt <viz cref="Implementor"/></lu> /// </li> /// </remarks> class Abstraction { // Vlastnost public Implementor Implementor { get ; nastavit ; } public virtual void Operace () { Implementor . operace (); } } /// <summary> /// Implementor /// </summary> /// <remarks> /// <li> /// <lu> definuje rozhraní pro implementační třídy. Nemusí /// přesně odpovídat rozhraní třídy <viz cref="Abstraction"/>. Ve skutečnosti mohou být obě /// rozhraní zcela odlišná. Typicky rozhraní třídy /// <viz cref="Implementor"/> představuje pouze primitivní operace, zatímco třída /// <viz cref="Abstrakce"/> definuje operace vyšší úrovně /// založené na těchto primitivech; <// lu> /// </li> /// </remarks> abstract class Implementor { public abstract void Operation (); } /// <summary> /// RefinedAbstraction /// </summary> /// <remarks> /// <li> /// <lu>rozšiřuje rozhraní definované abstrakcí <viz cref="Abstraction" / ></lu> /// </li> /// </remarks> class RefinedAbstraction : Abstraction { public override void Operation () { Implementor . operace (); } } /// <summary> /// ConcreteImplementor - konkrétní implementátor /// </summary> /// <remarks> /// <li> /// <lu>obsahuje konkrétní implementaci rozhraní <viz cref="Implementor" / ></lu> /// </li> /// </remarks> class ConcreteImplementorA : Implementor { public override void Operation () { Console . WriteLine ( "Operace ConcreteImplementorA" ); } } // "ConcreteImplementorB" class ConcreteImplementorB : Implementor { public override void Operation () { Console . WriteLine ( "Operace ConcreteImplementorB" ); } } }

Příklad PHP5

Zdrojový kód PHP5 interface IPrinter { public function printHeader ( $textHeader ); veřejná funkce printBody ( $textBody ); } class PdfPrinter implementuje IPrinter { public function printHeader ( $textHeader ) { echo 'Toto je vaše hlavička (' . $textHeader . ') v souboru pdf<br>' ; } public function printBody ( $textBody ) { echo 'Toto je vaše textové tělo (' . $textBody . ') v pdf souboru<br>' ; } } class ExcelPrinter implementuje IPrinter { public function printHeader ( $textHeader ) { echo 'Toto je vaše hlavička (' . $textHeader . ') v souboru xls<br>' ; } public function printBody ( $textBody ) { echo 'Toto je vaše textové tělo (' . $textBody . ') v xls souboru<br>' ; } } abstract class Report { protected $printer ; public function __construct ( IPprinter $printer ) { $this -> printer = $printer ; } public function printHeader ( $textHeader ) { $this -> tiskárna -> printHeader ( $textHeader ); } veřejná funkce printBody ( $textBody ) { $this -> tiskárna -> printBody ( $textBody ); } } class WeeklyReport extends Report { public function print ( array $text ) { $this -> printHeader ( $text [ 'header' ]); $this -> printBody ( $text [ 'body' ]); } } $report = new WeeklyReport ( new ExcelPrinter ()); $report -> print ([ 'header' => 'moje hlavička pro excel' , 'body' => 'moje tělo pro excel' ]); // Toto je vaše hlavička (moje hlavička pro Excel) v souboru xls</ br>Toto je vaše textové tělo (moje tělo pro Excel) v souboru xls<br> $report = new WeeklyReport ( new PdfPrinter ()); $report -> print ([ 'header' => 'moje hlavička pro pdf' , 'body' => 'moje tělo pro pdf' ]); // Toto je vaše záhlaví (moje záhlaví pro pdf) v souboru pdf</br>Toto je vaše textové tělo (moje tělo pro pdf) v souboru pdf<br>

Příklad PHP5.4

Zdrojový text v PHP5.4 vlastnost TData { private $data ; public function __construct ( pole $data ) { $this -> data = $data ; $this -> připravit (); } abstraktní chráněná funkce připravit (); } vlastnost TShow { private $content ; public function show () { print $this -> content ; } } class XmlFormat { use TData , TShow ; protected function Prepare () { $this -> content = '<?xml version="1.1" encoding="UTF-8" ?><root>' ; foreach ( $this -> data jako $name => $item ) { $this -> content .= "< $name > $item </ $name >" ; } $this -> content .= '</root>' ; } } class JsonFormat { use TData , TShow ; protected function Prepare () { $this -> content = json_encode ( $this -> data ); } } class SelfFormat { use TData , TShow ; chráněná funkce připravit () { $obsah = pole (); foreach ( $this -> data jako $jméno => $položka ) { $string = '' ; if ( is_string ( $name )) { $nLen = strlen ( $name ); $string .= "[jméno|řetězec( { $nLen } ){ { $jméno } }:val|" ; } if ( is_int ( $name )) { $string .= "[index|int{ { $name } }:val|" ; } if ( is_string ( $item )) { $vLen = strlen ( $item ); $string .= "string( $vLen ){ { $položka } " ; } if ( is_int ( $položka )) { $string .= "int{ { $položka } " ; } $string .= "}]" ; array_push ( $obsah , $řetězec ); } $this -> content = 'selfMadeDataFormat:Array(' . count ( $this -> data ) . '):' ; $this -> content .= implode ( ',' , $content ); $this -> content .= ':endSelfMadeDataFormat' ; } } $xml = new XmlFormat ( pole ( 'a' => 'b' , 'c' )); $json = new JsonFormat ( pole ( 'a' => 'b' , 'c' )); $self = new SelfFormat ( pole ( 'a' => 'b' , 'c' )); $self -> show (); /* selfMadeDataFormat:Array(2):[name|string(1){a}:val|string(1){b}],[index|int{0}:val|string(1){c}]: endSelfMadeDataFormat */ $xml -> show (); /* <?xml version="1.1" encoding="UTF-8" ?><root><a>b</a><0>c</0></root> */ $json -> zobrazit ( ); /* {"a":"b","0":"c"} */

Příklad CoffeeScript

Zdrojový text v jazyce CoffeeScript # Třída implementátoru IStorage get : (klíč) -> set : (klíč, hodnota) -> # Třída ConcreteImplementor IFlashStorage rozšiřuje IStorage # ... # Třída ConcreteImplementor IJavaStorage rozšiřuje IStorage # ... # Třída ConcreteImplementor ISessionStorage rozšiřuje IStorage # ... # Třída ConcreteImplementor ICookieStorage rozšiřuje IStorage # ... # Třída ConcreteImplementor IGhostStorage rozšiřuje IStorage # ... # Třída abstrakce AStorage # protected _implementer : if sessionStorage new ISessionStorage else if navigator . pluginy [ "Shockwave Flash" ] nový IFlashStorage else if navigator . javaEnabled () new IJavaStorage else if navigator . cookieEnabled nové ICookieStorage jinak nové IGhostStorage # public load : (key) -> forgot : (key) -> save : (key, value) -> # Třída RefinedAbstraction InfoStorage rozšiřuje zatížení AStorage : (klíč) -> @_implementer . získat ( "Informace: #{ klíč } " ) save : (klíč, hodnota) -> @_implementer . set ( "Info: #{ klíč } " , hodnota ) forgot : (key) -> @_implementer . set ( "Info: #{ klíč } " , null )

Příklad JavaScriptu

Zdrojový kód JavaScriptu // Implementor ("rozhraní") funkce Implementor () { this . operace = funkce () {}; } // ConcreteImplementor (Implementor implementace) function ConcreteImplementorA () { this . operace = function () { alert ( "ConcreteImplementorA.operation" ); }; } ConcreteImplementorA . prototyp = Objekt . vytvořit ( Implementor . prototyp ); ConcreteImplementorA . prototyp . konstruktor = ConcreteImplementorA ; function ConcreteImplementorB () { this . operace = function () { alert ( "ConcreteImplementorB.operation" ); }; } ConcreteImplementorB . prototyp = Objekt . vytvořit ( Implementor . prototyp ); ConcreteImplementorB . prototyp . konstruktor = ConcreteImplementorB ; // Funkce abstrakce Abstrakce () { var implementor ; toto . getImplementor = function () { // přístup k implementátoru z RefinedAbstraction return implementor ; }; toto . setImplementor = funkce ( val ) { implementor = val ; }; toto . operace = funkce () { implementátor . operace (); }; } // Funkce RefinedAbstraction RefinedAbstraction () { var abstr = new Abstraction (); toto . setImplementor = function ( val ) { abstr . setImplementor ( val ); }; toto . operace = funkce () { abstr . operace (); }; } // použití: var refAbstr = new RefinedAbstraction (); refAbstr . setImplementor ( new ConcreteImplementorA () ); refAbstr . operace (); // "Operace ConcreteImplementorA." refAbstr . setImplementor ( new ConcreteImplementorB () ); refAbstr . operace (); // "Operace ConcreteImplementorB."

Bez nutnosti přetěžovat metody abstrakce lze RefinedAbstraction výrazně zjednodušit:

function RefinedAbstraction () { Abstrakce . zavolat ( toto ); }

Můžete také uložit odkazy na přetížené metody ihned po vytvoření instance Abstrakce:

function RefinedAbstraction () { Abstrakce . zavolat ( toto ); var abstr_setImplementor = this . setImplementor ; toto . setImplementor = function ( val ) { abstr_setImplementor ( val ); }; }

Příklad VB.NET

Zdrojový text v jazyce VB.NET most jmenného prostoru ' Program - Třída Testovací aplikace Program Sdílený Podhlavní ( ) Dim AB As Abstraction = New RefinedAbstraction () ' Nainstalujte implementaci a zavolejte AB . Implementor = New ConcreteImplementorA () AB . operace () ' Nainstalujte implementaci a zavolejte AB . Implementor = New ConcreteImplementorB () AB . operace () ' Počkejte na akci uživatele Console . Číst () End Sub End Class ''' <summary> ''' Abstrakce - abstrakce ''' </summary> ''' <remarks> ''' <li> ''' <lu>definuje rozhraní abstrakce;</lu> ''' < lu >ukládá odkaz na objekt <viz cref="Implementor"/></lu> ''' </li> ''' </remarks> Class Abstraction Protected m_implementor As Implementor ' Public Property Implementor () Jako Implementor Get Return m_implementor End Get Set ( ByVal value As Implementor ) m_implementor = hodnota End Set End Property Veřejná přepsatelná dílčí operace () m_implementor . Operace () End Sub End Class ''' <summary> ''' Implementor ''' </summary> ''' <remarks> ''' <li> ''' <lu> definuje rozhraní pro implementační třídy. Nemusí přesně odpovídat ''' rozhraní třídy <viz cref="Abstrakce"/>. Ve skutečnosti mohou být obě ''' rozhraní zcela odlišná. Obvykle rozhraní třídy ''' <viz cref="Implementor"/> představuje pouze primitivní operace a třída ''' <viz cref="Abstrakce"/> definuje operace vyšší úrovně založené na těchto primitivech ''';< / lu> ''' </li> ''' </remarks> MustInherit Class Implementor Public MustOverride Sub Operation () End Class ''' <summary> ''' RefinedAbstraction - rafinovaná abstrakce ''' </summary> ''' <remarks> ''' <li> ''' <lu> rozšiřuje rozhraní definované abstrakcí <viz cref= "Abstrakce" /></lu> ''' </li> ''' </remarks> Třída RefinedAbstraction zdědí abstrakci Public Overrides Sub Operation () implementátor . Operace () End Sub End Class ''' <summary> ''' ConcreteImplementor - konkrétní implementátor ''' </summary> ''' <remarks> ''' <li> ''' <lu>obsahuje konkrétní implementaci rozhraní <viz cref= "Implementor"/ ></lu> ''' </li> ''' </remarks> Třída ConcreteImplementorA zdědí implementátor Public Overrides Sub Operation () Console . WriteLine ( "Operace ConcreteImplementorA" ) End Sub End Class ' Třída "ConcreteImplementorB" ConcreteImplementorB zdědí implementor Public Overrides Sub Operation () Console . WriteLine ( "Operace ConcreteImplementorB" ) End Sub End Class End Namespace

Příklad Pythonu

Zdrojový kód v Pythonu # Implementor class DrawingAPI : def drawCircle ( self , x , y , radius ): pass # ConcreteImplementor 1/2 class DrawingAPI1 ( DrawingAPI ): def drawCircle ( self , x , y , poloměr ): print "API1.circle na %f : %f poloměr %f " % ( x , y , poloměr ) # ConcreteImplementor 2/2 class DrawingAPI2 ( DrawingAPI ): def drawCircle ( self , x , y , poloměr ): print "API2.circle na %f : %f poloměr %f " % ( x , y , poloměr ) # Třída abstrakce Tvar : # Nízkoúrovňové def draw ( self ): pass # Vysoká úroveň def resizeByPercentage ( self , pct ): pass # Třída Refined Abstraction CircleShape ( Shape ): def __init__ ( self , x , y , poloměr , drawingAPI ): self . __x = x vlastní . __y = y self . __radius = rádius self . __drawingAPI = drawingAPI # low-level tj. implementace specifická def draw ( self ): self . __drawingAPI . drawCircle ( self . __x , self . __y , self . __radius ) # high-level tj. abstrakce specifická def resizeByPercentage ( self , pct ): self . __poloměr *= pct def main (): tvary = [ CircleShape ( 1 , 2 , 3 , DrawingAPI1 ()), CircleShape ( 5 , 7 , 11 , DrawingAPI2 ()) ] pro tvar ve tvarech : tvar . tvar resizeByPercentage ( 2,5 ) . kreslit () if __name__ == "__main__" : hlavní ()

Literatura

  • 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. : " Petr ", 2007. - S. 366. - ISBN 978-5-469-01136-1 . (také ISBN 5-272-00355-1 )

Odkazy