Bro (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 11 redigeringar .
Bro
Bro
Sorts strukturell
Beskrivs i Design Patterns Ja

Bromönstret är ett strukturellt  designmönster som används i mjukvarudesign för att "separera abstraktion och implementering så att de kan förändras oberoende av varandra." Bromönstret använder inkapsling , aggregering och kan använda arv för att dela ansvar mellan klasser.

Syfte

När en klass ändras ofta blir fördelarna med den objektorienterade metoden mycket användbara, vilket gör att du kan göra ändringar i programmet med minimal kunskap om programmets implementering. Bromönstret är användbart där inte bara själva klassen ändras ofta, utan också vad den gör.

Beskrivning

När abstraktion och implementering separeras kan de förändras oberoende av varandra. Med andra ord, när det implementeras genom bryggmönstret, stör ändring av gränssnittets struktur inte ändring av implementeringens struktur. Betrakta en sådan abstraktion som en figur. Det finns många typer av former, alla med sina egna egenskaper och metoder. Det finns dock något som förenar alla figurer. Till exempel måste varje form kunna rita sig själv, skala etc. Samtidigt kan ritningsgrafik skilja sig beroende på typ av OS eller grafikbibliotek. Former måste kunna rita sig själva i olika grafiska miljöer, men det är opraktiskt att implementera alla ritmetoder i varje form, eller att modifiera formen varje gång ritmetoden ändras. I det här fallet hjälper bromönstret, så att du kan skapa nya klasser som kommer att implementera ritning i olika grafiska miljöer. Med detta tillvägagångssätt är det mycket enkelt att lägga till både nya former och sätt att rita dem.

Kopplingen som representeras av pilen i diagrammen kan ha två betydelser: a) "en sort", i enlighet med Liskov-substitutionsprincipen, och b) en av de möjliga implementeringarna av abstraktion. Språk använder vanligtvis arv för att implementera både a) och b), vilket tenderar att blåsa upp klasshierarkier.

Bron tjänar just till att lösa detta problem: objekt skapas i par från ett objekt av klassen av hierarkin A och hierarki B, arv inom hierarkin A har betydelsen av "variant" enligt Liskov, och för begreppet " implementering av abstraktion” används en länk från objekt A till dess parade objekt B.

Användning

Java AWT - arkitekturen är helt baserad på detta mönster - java.awt.xxx-hierarkin för handtag och sun.awt.xxx för implementeringar.

Exempel

C++ exempel

Källtext i C++ #include <iostream> använder namnutrymme std ; klasslåda { _ offentliga : virtuell void drawCircle ( int x , int y , int radie ) = 0 ; }; klass SmallCircleDrawer : public Drawer { offentliga : const dubbelradieMultiplier = 0,25 ; _ void drawCircle ( int x , int y , int radie ) åsidosätta { cout << "Liten cirkel mitt " << x << ", " << y << " radius = " << radius * radiusMultiplier << endl ; } }; class LargeCircleDrawer : public Drawer { offentliga : const dubbelradieMultiplier = 10 ; _ void drawCircle ( int x , int y , int radie ) åsidosätta { cout << "Stor cirkel mitt " << x << ", " << y << " radius = " << radius * radiusMultiplier << endl ; } }; klass Shape { skyddad : Låda * låda ; offentliga : Form ( Låda * drw ) { låda = drw ; } form () {} virtuell void draw () = 0 ; virtual void enlargeRadius ( int multiplikator ) = 0 ; }; class Circle : public Shape { int x , y , radie ; offentliga : Cirkel ( int _x , int _y , int _radius , Drawer * drw ) { låda = drw ; setX ( _x ); setY ( _y ); setRadius ( _radius ); } void draw () åsidosätta { drawer -> drawCircle ( x , y , radie ); } void enlargeRadius ( int multiplikator ) åsidosätt { radie *= multiplikator ; } void setX ( int_x ) { _ x = _x ; } void setY ( int_y ) { _ y = _y _ } void setRadius ( int _radius ) { radie = _radius ; } }; int main ( int argc , char * argv []) { Shape * shapes [ 2 ] = { new Circle ( 5 , 10 , 10 , new LargeCircleDrawer ()), new Circle ( 20 , 30 , 100 , new SmallCircleDrawer ())}; för ( int i = 0 ; i < 2 ; i ++ ) { former [ i ] -> rita (); } returnera 0 ; } // Utdata Stor cirkelcentrum = 5 , 10 radie = 100 Liten cirkelcentrum = 20 , 30 radie = 25,0 _

Java-exempel

Java -källa public interface Drawer { public void drawCircle ( int x , int y , int radie ); } public class SmallCircleDrawer implementerar Drawer { offentlig statisk slutlig dubbelradieMultiplier = 0,25 ; _ @Override public void drawCircle ( int x , int y , int radius ) { System . ut . println ( "Liten cirkelcentrum = " + x + "," + y + " radie = " + radie * radiusMultiplier ); } } public class LargeCircleDrawer implementerar Drawer { public static final int radiusMultiplier = 10 ; @Override public void drawCircle ( int x , int y , int radius ) { System . ut . println ( "Stor cirkelcentrum = " + x + "," + y + " radie = " + radie * radiusMultiplier ); } } offentlig abstrakt klass Shape { skyddad Lådlåda ; _ skyddad Form ( Lådlåda ) { detta . låda = låda ; } offentlig abstrakt void draw (); public abstract void enlargeRadius ( int multiplikator ); } offentlig klass Cirkel utökar Shape { privat int x ; privat int y ; privat int radie ; public Circle ( int x , int y , int radius , Drawer drawer ) { super ( drawer ); setX ( x ); setY ( y ); setRadius ( radie ); } @Override public void draw () { drawer . drawCircle ( x , y , radie ); } @Override public void enlargeRadius ( int multiplikator ) { radius *= multiplikator ; } public int getX () { return x ; } public int getY () { return y ; } public int getRadius ( ) { returradie ; } public void setX ( int x ) { detta . x = x ; } public void setY ( int y ) { this . y = y _ } public void setRadius ( int radius ) { detta . radie = radie ; } } // Klass som visar hur designmönstret "Bron" fungerar. public class Application { public static void main ( String [] args ){ Shape [] shapes = { new Circle ( 5 , 10 , 10 , new LargeCircleDrawer ()), new Circle ( 20 , 30 , 100 , new SmallCircleDrawer ())}; för ( Shape next : shapes ) nästa . rita (); } } // Utdata Stor cirkelcentrum = 5 , 10 radie = 100 Liten cirkelcentrum = 20 , 30 radie = 25,0 _

Exempel i C#

Källtext i C# använder System ; namnområde Bridge { // MainApp-testapplikation class MainApp { static void Main () { Abstraction ab = new RefinedAbstraction (); // Ställ in implementering och anrop ab . Implementor = new ConcreteImplementorA (); ab . operationer (); // Ändra implementering och ring ab . Implementor = new ConcreteImplementorB (); ab . operationer (); // Vänta på användarkonsolen . läs (); } } /// <sammanfattning> /// Abstraktion - abstraktion /// </summary> /// <remarks> /// <li> /// <lu>definiera abstraktionsgränssnittet;</lu> /// < lu >lagrar en referens till ett objekt <see cref="Implementor"/></lu> /// </li> /// </remarks> class Abstraction { // Property public Implementor Implementor { get ; set ; } public virtual void Operation () { Implementor . operationer (); } } /// <sammanfattning> /// Implementator /// </summary> /// <remarks> /// <li> /// <lu> definierar ett gränssnitt för implementeringsklasser. Det behöver inte /// exakt matcha <see cref="Abstraction"/> klassgränssnittet. Faktum är att båda ///-gränssnitten kan vara helt olika. Typiskt representerar klassgränssnittet /// <see cref="Implementor"/> endast primitiva operationer, medan klassen /// <see cref="Abstraction"/> definierar operationer på högre nivå /// baserat på dessa primitiver; <// lu> /// </li> /// </remarks> abstrakt klass Implementor { public abstract void Operation (); } /// <summary> /// RefinedAbstraction /// </summary> /// <remarks> /// <li> /// <lu>förlänger gränssnittet som definieras av abstraktionen <see cref="Abstraction" / ></lu> /// </li> /// </remarks> class RefinedAbstraction : Abstraktion { public override void Operation () { Implementor . operationer (); } } /// <sammanfattning> /// ConcreteImplementor - concrete implementor /// </summary> /// <remarks> /// <li> /// <lu>innehåller konkret implementering av gränssnittet <see cref="Implementor" / ></lu> /// </li> /// </remarks> class ConcreteImplementorA : Implementor { public override void Operation () { Console . WriteLine ( "ConcreteImplementorA Operation" ); } } // "ConcreteImplementorB" class ConcreteImplementorB : Implementor { public override void Operation () { Console . WriteLine ( "ConcreteImplementorB Operation" ); } } }

PHP5 exempel

PHP5 källkod gränssnitt IPrinter { public function printHeader ( $textHeader ); public function printBody ( $textBody ); } class PdfPrinter implementerar IPrinter { public function printHeader ( $textHeader ) { echo 'Detta är din rubrik (' . $textHeader . ') i pdf-filen<br>' ; } public function printBody ( $textBody ) { echo 'Detta är din textkropp (' . $textBody . ') i pdf-filen<br>' ; } } class ExcelPrinter implementerar IPrinter { public function printHeader ( $textHeader ) { echo 'Detta är din rubrik (' . $textHeader . ') i xls-filen<br>' ; } public function printBody ( $textBody ) { echo 'Detta är din textkropp (' . $textBody . ') i xls-filen<br>' ; } } abstrakt klass Rapport { protected $printer ; public function __construct ( IPrinter $printer ) { $this -> printer = $printer ; } public function printHeader ( $textHeader ) { $this -> printer -> printHeader ( $textHeader ); } public function printBody ( $textBody ) { $this -> printer -> printBody ( $textBody ); } } class WeeklyReport utökar Rapport { public function print ( array $text ) { $this -> printHeader ( $text [ 'header' ]); $this -> printBody ( $text [ 'kropp' ]); } } $report = new WeeklyReport ( ny ExcelPrinter ()); $report -> print ([ 'header' => 'min rubrik för excel' , 'body' => 'min kropp för excel' ]); // Det här är din rubrik (min rubrik för excel) i xls-filen</ br>Det här är din textkropp (min text för excel) i xls-filen<br> $report = new WeeklyReport ( new PdfPrinter ()); $report -> print ([ 'header' => 'min rubrik för pdf' , 'body' => 'min kropp för pdf' ]); // Det här är din rubrik (min rubrik för pdf) i pdf-filen</br>Det här är din textkropp (min brödtext för pdf) i pdf-filen<br>

PHP5.4 exempel

Källtext i PHP5.4 egenskap TData { privat $data ; public function __construct ( array $data ) { $this -> data = $data ; $this -> prepare (); } abstrakt skyddad funktion preparera (); } egenskap TShow { privat $content ; public function show () { print $this -> content ; } } class XmlFormat { använd TData , TShow ; skyddad funktion prepare () { $this -> content = '<?xml version="1.1" encoding="UTF-8" ?><root>' ; foreach ( $this -> data som $name => $item ) { $this -> content .= "< $name > $item </ $name >" ; } $this -> innehåll .= '</root>' ; } } class JsonFormat { använd TData , TShow ; skyddad funktion preparera () { $this -> content = json_encode ( $this -> data ); } } class SelfFormat { använd TData , TShow ; skyddad funktion preparera () { $content = array (); foreach ( $this -> data som $name => $item ) { $string = '' ; if ( är_sträng ( $namn )) { $nLen = strlen ( $namn ); $string .= "[namn|sträng( { $nLen } ){ { $name } }:val|" ; } if ( is_int ( $name )) { $string .= "[index|int{ { $name } }:val|" ; } if ( is_string ( $item )) { $vLen = strlen ( $item ); $string .= "string( $vLen ){ { $item } " ; } if ( is_int ( $item )) { $string .= "int{ { $item } " ; } $string .= "}]" ; array_push ( $content , $string ); } $this -> content = 'selfMadeDataFormat:Array(' . count ( $this -> data ) . '):' ; $this -> content .= implode ( ',' , $content ); $this -> content .= ':endSelfMadeDataFormat' ; } } $xml = nytt XmlFormat ( array ( 'a' => 'b' , 'c' )); $json = nytt JsonFormat ( array ( 'a' => 'b' , 'c' )); $self = new SelfFormat ( array ( 'a' => 'b' , 'c' )); $self -> visa (); /* 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 -> show ( ); /* {"a":"b","0":"c"} */

CoffeeScript-exempel

Källtext på CoffeeScript- språket # Implementatorklass IStorage get : (nyckel) -> set: (nyckel, värde) -> # ConcreteImplementor klass IFlashStorage utökar IStorage # ... # ConcreteImplementor klass IJavaStorage utökar IStorage # ... # ConcreteImplementor klass ISessionStorage utökar IStorage # ... # ConcreteImplementor klass ICookieStorage utökar ISlagring # ... # ConcreteImplementor klass IGhostStorage utökar IStorage # ... # Abstraktionsklass AStorage # protected _implementer : om sessionStorage ny ISessionStorage annat om navigator . plugins [ "Shockwave Flash" ] nya IFlashStorage annat om navigator . javaEnabled () ny IJavaStorage else if navigator . cookieEnabled ny ICookieStorage annars ny IGhostStorage # public load : (nyckel) -> glömde : (nyckel) -> spara : (nyckel, värde) -> # RefinedAbstraction klass InfoStorage utökar ASlagringsbelastning : (nyckel) -> @_implementer . ( "Info: #{ nyckel } " ) save : (nyckel, värde) -> @_implementer . set ( "Info: #{ nyckel } " , värde ) glömde : (nyckel) -> @_implementer . set ( "Info: #{ key } " , null )

JavaScript-exempel

JavaScript -källkod // Implementor ("gränssnitt") funktion Implementor () { this . operation = funktion () {}; } // ConcreteImplementor (Implementation Implementor) funktion ConcreteImplementorA () { this . operation = function () { alert ( "ConcreteImplementorA.operation" ); }; } ConcreteImplementorA . prototyp = Objekt . skapa ( Implementor . prototyp ); ConcreteImplementorA . prototyp . konstruktor = ConcreteImplementorA ; function ConcreteImplementorB () { this . operation = function () { alert ( "ConcreteImplementorB.operation" ); }; } ConcreteImplementorB . prototyp = Objekt . skapa ( Implementor . prototyp ); ConcreteImplementorB . prototyp . konstruktor = ConcreteImplementorB ; // Abstraktionsfunktion Abstraktion ( ) { var implementor ; detta . getImplementor = function () { // åtkomst till implementorn från RefinedAbstraction return implementor ; }; detta . setImplementor = function ( val ) { implementor = val ; }; detta . operation = function () { implementator . operation (); }; } // RefinedAbstraction function RefinedAbstraction () { var abstr = new Abstraction (); detta . setImplementor = function ( val ) { abstr . setImplementor ( val ); }; detta . operation = funktion () { abstr . operation (); }; } // användning: var refAbstr = new RefinedAbstraction (); refAbstr . setImplementor ( ny ConcreteImplementorA () ); refAbstr . operation (); // "ConcreteImplementorA. operation" refAbstr . setImplementor ( ny ConcreteImplementorB () ); refAbstr . operation (); // "ConcreteImplementorB. operation"

Utan att behöva överbelasta abstraktionsmetoder kan RefinedAbstraction avsevärt förenklas:

function RefinedAbstraction () { Abstraktion . ring ( detta ); }

Du kan också spara referenser till överbelastade metoder omedelbart efter att abstraktionen instansierats:

function RefinedAbstraction () { Abstraktion . ring ( detta ); var abstr_setImplementor = detta . setImplementor ; detta . setImplementor = function ( val ) { abstr_setImplementor ( val ); }; }

VB.NET exempel

Källtext på språket VB.NET namnrymdsbrygga _ ' Program - Test Application Class Program Shared Sub Main () Dim AB As Abstraction = New RefinedAbstraction () ' Installera implementering och ring AB . Implementor = New ConcreteImplementorA () AB . operation () ' Installera implementering och ring AB . Implementor = New ConcreteImplementorB () AB . operation () " Vänta på användaråtgärdskonsolen . Läs () End Sub End Class ''' <summary> ''' Abstraktion - abstraktion ''' </summary> ''' <remarks> ''' <li> ''' <lu>definiera abstraktionsgränssnittet;</lu> ''' < lu >lagrar en referens till ett objekt <see cref="Implementor"/></lu> ' '' </li> ''' </remarks > Klassabstraktionsskyddad m_implementor Som Implementor ' Public Property Implementor () Som Implementor Get Return m_implementor End Get Set ( ByVal value As Implementor ) m_implementor = värde End Set End Property Public Overridable Sub Operation () m_implementor . Operation () End Sub End Class ''' <summary> ''' Implementator ''' </summary> ''' <remarks> ''' <li> ''' <lu> definierar ett gränssnitt för implementeringsklasser. Det behöver inte exakt ''' matcha klassgränssnittet <see cref="Abstraction"/>. Faktum är att båda '''-gränssnitten kan vara helt olika. Vanligtvis representerar klassgränssnittet ''' <see cref="Implementor"/> endast primitiva operationer, och klassen ''' <see cref="Abstraction"/> definierar operationer på högre nivå baserat på dessa primitiver ''';< / lu> ''' </li> ''' </remarks> MustInherit Class Implementor Public MustOverride Sub Operation () End Class ''' <summary> ''' RefinedAbstraction - en förfinad abstraktion ''' </summary> ''' <remarks> ''' <li> ''' <lu> utökar gränssnittet som definieras av abstraktionen <see cref= "Abstraktion" /></lu> ''' </li> ''' </remarks> Klass FörfinadAbstraktion ärver abstraktion Public Overrides Sub Operation () implementerare . Operation () End Sub End Class ''' <summary> ''' ConcreteImplementor - en konkret implementerare ''' </summary> ''' <remarks> ''' <li> ''' <lu>innehåller en konkret implementering av gränssnittet <see cref= "Implementor"/ ></lu> ''' </li> ''' </remarks> Klass ConcreteImplementorA ärver Implementor Offentlig åsidosättning underoperation ( ) konsol . WriteLine ( "ConcreteImplementorA Operation" ) End Sub End Class ' "ConcreteImplementorB" Klass ConcreteImplementorB ärver Implementor Offentlig åsidosättning underoperation ( ) konsol . WriteLine ( "ConcreteImplementorB Operation" ) End Sub End Class End Namespace

Python-exempel

Källkod i Python # Implementator class DrawingAPI : def drawCircle ( self , x , y , radie ): pass # ConcreteImplementor 1/2 class DrawingAPI1 ( DrawingAPI ): def drawCircle ( self , x , y , radius ): print "API1.circle at %f : %f radius %f " % ( x , y , radius ) # ConcreteImplementor 2/2 class DrawingAPI2 ( DrawingAPI ): def drawCircle ( self , x , y , radius ): print "API2.circle at %f : %f radius %f " % ( x , y , radius ) # Abstraktionsklass Form : # Lågnivå def draw ( själv ): godkänt # Def resizeByPercentage på hög nivå ( själv , pct ): godkänt # Förfinad abstraktionsklass CircleShape ( Shape ) : def __init__ ( self , x , y , radius , drawingAPI ): self . __x = x själv . __y = y själv . __radius = radie själv . __drawingAPI = drawingAPI # lågnivå dvs. Implementeringsspecifik def draw ( self ): själv . __drawingAPI . drawCircle ( själv . __x , själv . __y , själv . __radius ) # high-level dvs abstraktionsspecifik def resizeByPercentage ( self , pct ): self . __radie *= pct def main (): former = [ CircleShape ( 1 , 2 , 3 , DrawingAPI1 ()), CircleShape ( 5 , 7 , 11 , DrawingAPI2 ()) ] för form i former : form . resizeByPercentage ( 2,5 ) form . rita () if __name__ == "__main__" : main ()

Litteratur

  • 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 )

Länkar