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 .
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