Bro (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; checks kræver 11 redigeringer .
Bro
Bro
Type strukturel
Beskrevet i Design Patterns Ja

Bromønsteret er et strukturelt  designmønster , der bruges i softwaredesign for at "adskille abstraktion og implementering , så de kan ændre sig uafhængigt." Bromønsteret bruger indkapsling , aggregering og kan bruge arv for at dele ansvar mellem klasser.

Formål

Når en klasse skifter ofte, bliver fordelene ved den objektorienterede tilgang meget nyttige, så du kan foretage ændringer i programmet med minimal viden om programimplementeringen. Bromønsteret er nyttigt, hvor ikke kun selve klassen ændrer sig ofte, men også hvad den gør.

Beskrivelse

Når abstraktion og implementering er adskilt, kan de ændre sig uafhængigt. Med andre ord, når det implementeres gennem bromønsteret, vil ændring af strukturen af ​​grænsefladen ikke forstyrre ændring af strukturen af ​​implementeringen. Betragt en sådan abstraktion som en figur. Der er mange former for former, hver med sine egne egenskaber og metoder. Der er dog noget, der forener alle figurerne. For eksempel skal hver form kunne tegne sig selv, skalere osv. Samtidig kan tegnegrafik variere afhængigt af typen af ​​OS eller grafikbibliotek. Former skal kunne tegne sig selv i forskellige grafiske miljøer, men det er upraktisk at implementere alle tegnemetoderne i hver figur, eller at ændre formen, hver gang tegnemetoden ændres. I dette tilfælde hjælper bromønsteret, så du kan oprette nye klasser, der implementerer tegning i forskellige grafiske miljøer. Ved at bruge denne tilgang er det meget nemt at tilføje både nye former og måder at tegne dem på.

Forbindelsen repræsenteret af pilen i diagrammerne kan have 2 betydninger: a) "en slags", i overensstemmelse med Liskov substitutionsprincippet, og b) en af ​​de mulige implementeringer af abstraktion. Sprog bruger typisk arv til at implementere både a) og b), som har en tendens til at blæse klassehierarkier op.

Broen tjener netop til at løse dette problem: objekter skabes i par fra et objekt af klassen af ​​hierarkiet A og hierarki B, arv inden for hierarkiet A har betydningen af ​​"variant" ifølge Liskov, og for begrebet " implementering af abstraktion” bruges et link fra objekt A til dets parrede objekt B.

Brug

Java AWT - arkitekturen er fuldstændig baseret på dette mønster - java.awt.xxx-hierarkiet for håndtag og sun.awt.xxx for implementeringer.

Eksempler

C++ eksempel

Kildetekst i C++ #include <iostream> bruger navneområde std ; klasseskuffe { _ offentligt : virtuel void drawCircle ( int x , int y , int radius ) = 0 ; }; klasse SmallCircleDrawer : offentlig skuffe { offentligt : const dobbelt radiusMultiplier = 0,25 ; void drawCircle ( int x , int y , int radius ) tilsidesætte { cout << "Lille cirkel center " << x << ", " << y << " radius = " << radius * radiusMultiplier << endl ; } }; klasse LargeCircleDrawer : offentlig skuffe { offentligt : const dobbelt radiusMultiplier = 10 ; void drawCircle ( int x , int y , int radius ) tilsidesætte { cout << "Stor cirkel center " << x << ", " << y << " radius = " << radius * radiusMultiplier << endl ; } }; klasse Form { beskyttet : Skuffe * skuffe ; offentligt : Form ( Skuffe * drw ) { skuffe = drw ; } form () {} virtual void draw () = 0 ; virtual void enlargeRadius ( int multiplikator ) = 0 ; }; klasse Cirkel : offentlig Form { int x , y , radius ; offentligt : Cirkel ( int _x , int _y , int _radius , Skuffe * drw ) { skuffe = drw ; sætX ( _x ); sætY ( _y ); sætRadius ( _radius ); } void draw () tilsidesætte { skuffe -> drawCircle ( x , y , radius ); } void enlargeRadius ( int multiplikator ) tilsidesætte { radius *= multiplikator ; } void sætX ( int_x ) { _ x = _x ; } void sætY ( int_y ) { _ y = _y _ } void setRadius ( int _radius ) { radius = _radius ; } }; int main ( int argc , char * argv []) { Shape * shapes [ 2 ] = { new Circle ( 5 , 10 , 10 , new LargeCircleDrawer ()), ny Cirkel ( 20 , 30 , 100 , ny SmallCircleDrawer ())}; for ( int i = 0 ; i < 2 ; i ++ ) { former [ i ] -> tegne (); } returnere 0 ; } // Output Stor cirkelcentrum = 5 , 10 radius = 100 Lille cirkelcentrum = 20 , 30 radius = 25,0 _

Java-eksempel

Java kilde offentlig grænseflade Skuffe { public void drawCircle ( int x , int y , int radius ); } public class SmallCircleDrawer implementerer Skuffe { offentlig statisk endelig dobbeltradiusMultiplier = 0,25 ; _ @Override public void drawCircle ( int x , int y , int radius ) { System . ud . println ( "Lille cirkel center = " + x + "," + y + " radius = " + radius * radiusMultiplier ); } } public class LargeCircleDrawer implementerer Skuffe { offentlig statisk endelig int radiusMultiplier = 10 ; @Override public void drawCircle ( int x , int y , int radius ) { System . ud . println ( "Stor cirkelcenter = " + x + "," + y + " radius = " + radius * radiusMultiplier ); } } offentlig abstrakt klasse Shape { beskyttet Skuffeskuffe ; _ beskyttet Form ( skuffeskuffe ) { denne . skuffe = skuffe ; } offentlig abstrakt void draw (); offentlig abstrakt void enlargeRadius ( int multiplikator ); } offentlig klasse Cirkel udvider Shape { privat int x ; privat int y ; privat int radius ; offentlig Cirkel ( int x , int y , int radius , Skuffeskuffe ) { super ( skuffe ) ; sætX ( x ); sætY ( y ); sætRadius ( radius ); } @Override public void draw () { skuffe . tegneCirkel ( x , y , radius ); } @Override public void enlargeRadius ( int multiplikator ) { radius *= multiplikator ; } public int getX () { return x ; } public int getY () { return y ; } public int getRadius ( ) { returradius ; } public void setX ( int x ) { dette . x = x ; } public void setY ( int y ) { this . y = y _ } public void setRadius ( int radius ) { dette . radius = radius ; } } // Klasse, der viser, hvordan "Bridge"-designmønsteret fungerer. 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 ())}; for ( Shape next : shapes ) næste . tegne (); } } // Output Stor cirkelcentrum = 5 , 10 radius = 100 Lille cirkelcentrum = 20 , 30 radius = 25,0 _

Eksempel i C#

Kildetekst i C# bruger System ; navneområde Bridge { // MainApp-testapplikation klasse MainApp { static void Main () { Abstraction ab = new RefinedAbstraction (); // Indstil implementering og kald ab . Implementor = new ConcreteImplementorA (); ab . operationer (); // Ændre implementering og kald ab . Implementor = new ConcreteImplementorB (); ab . operationer (); // Vent på brugerkonsollen . læs (); } } /// <resumé> /// Abstraktion - abstraktion /// </summary> /// <bemærkninger> /// <li> /// <lu>definer abstraktionsgrænsefladen;</lu> /// < lu >gemmer en reference til et objekt <see cref="Implementor"/></lu> /// </li> /// </remarks> class Abstraction { // Property public Implementor Implementor { get ; sæt ; } public virtual void Operation () { Implementor . operationer (); } } /// <summary> /// Implementor /// </summary> /// <remarks> /// <li> /// <lu> definerer en grænseflade for implementeringsklasser. Det behøver ikke /// at svare nøjagtigt til <see cref="Abstraction"/> klassegrænsefladen. Faktisk kan begge ///-grænseflader være helt forskellige. Klassegrænsefladen /// <see cref="Implementor"/> repræsenterer typisk kun primitive operationer, mens klassen /// <see cref="Abstraction"/> definerer operationer på højere niveau /// baseret på disse primitiver; <// lu> /// </li> /// </remarks> abstrakt klasse Implementor { public abstract void Operation (); } /// <summary> /// RefinedAbstraction /// </summary> /// <remarks> /// <li> /// <lu>udvider grænsefladen defineret af abstraktionen <see cref="Abstraction" / ></lu> /// </li> /// </remarks> class RefinedAbstraction : Abstraktion { public override void Operation () { Implementor . operationer (); } } /// <resumé> /// ConcreteImplementor - konkret implementor /// </summary> /// <remarks> /// <li> /// <lu>indeholder konkret implementering af interface <see cref="Implementor" / ></lu> /// </li> /// </remarks> class ConcreteImplementorA : Implementor { public override void Operation () { Console . WriteLine ( "ConcreteImplementorA Operation" ); } } // "BetonImplementorB" klasse ConcreteImplementorB : Implementor { public override void Operation () { Console . WriteLine ( "ConcreteImplementorB Operation" ); } } }

PHP5 eksempel

PHP5 kildekode interface IPrinter { public function printHeader ( $textHeader ); public function printBody ( $textBody ); } klasse PdfPrinter implementerer IPrinter { public function printHeader ( $textHeader ) { echo 'Dette er din header (' . $textHeader . ') i pdf-filen<br>' ; } public function printBody ( $textBody ) { echo 'Dette er din teksttekst (' . $textBody . ') i pdf-filen<br>' ; } } klasse ExcelPrinter implementerer IPrinter { public function printHeader ( $textHeader ) { echo 'Dette er din header (' . $textHeader . ') i xls-filen<br>' ; } public function printBody ( $textBody ) { echo 'Dette er din teksttekst (' . $textBody . ') i xls-filen<br>' ; } } abstrakt klasse Rapport { protected $printer ; offentlig funktion __construct ( IPrinter $printer ) { $this -> printer = $printer ; } public function printHeader ( $textHeader ) { $this -> printer -> printHeader ( $textHeader ); } public function printBody ( $textBody ) { $this -> printer -> printBody ( $textBody ); } } class WeeklyReport udvider Rapport { public function print ( array $text ) { $this -> printHeader ( $text [ 'header' ]); $this -> printBody ( $tekst [ 'body' ]); } } $report = new WeeklyReport ( ny ExcelPrinter ()); $report -> print ([ 'header' => 'min header for excel' , 'body' => 'min krop for excel' ]); // Dette er din header (min overskrift for excel) i xls-filen</ br>Dette er din teksttekst (min krop for excel) i xls-filen<br> $report = new WeeklyReport ( ny PdfPrinter ()); $report -> print ([ 'header' => 'min sidehoved til pdf' , 'body' => 'min krop til pdf' ]); // This is your header (min header for pdf) in the pdf file</br>This is your text body (my body for pdf) in the pdf file<br>

PHP5.4 eksempel

Kildetekst i PHP5.4 egenskab TData { private $data ; offentlig funktion __construct ( array $data ) { $this -> data = $data ; $this -> forberede (); } abstrakt beskyttet funktion forberede (); } egenskab TShow { privat $indhold ; public function show () { print $this -> content ; } } klasse XmlFormat { brug TData , TShow ; beskyttet funktion prepare () { $this -> content = '<?xml version="1.1" encoding="UTF-8" ?><root>' ; foreach ( $this -> data som $name => $item ) { $this -> content .= "< $name > $item </ $name >" ; } $this -> content .= '</root>' ; } } klasse JsonFormat { brug TData , TShow ; beskyttet funktion forberede () { $this -> content = json_encode ( $this -> data ); } } klasse SelfFormat { brug TData , TShow ; beskyttet funktion forberede () { $content = array (); foreach ( $this -> data som $navn => $item ) { $string = '' ; if ( er_streng ( $navn )) { $nLen = strlen ( $navn ); $string .= "[navn|streng( { $nLen } ){ { $navn } }:val|" ; } if ( is_int ( $navn )) { $string .= "[indeks|int{ { $navn } }:val|" ; } if ( is_string ( $item )) { $vLen = strlen ( $item ); $string .= "string( $vLen ){ { $item } " ; } if ( is_int ( $item )) { $string .= "int{ { $item } " ; } $string .= "}]" ; array_push ( $indhold , $streng ); } $this -> content = 'selfMadeDataFormat:Array(' . count ( $this -> data ) . '):' ; $this -> content .= implode ( ',' , $content ); $this -> content .= ':endSelfMadeDataFormat' ; } } $xml = nyt XmlFormat ( array ( 'a' => 'b' , 'c' )); $json = nyt JsonFormat ( array ( 'a' => 'b' , 'c' )); $self = new SelfFormat ( array ( 'a' => 'b' , 'c' )); $selv -> vis (); /* selfMadeDataFormat:Array(2):[navn|streng(1){a}:val|streng(1){b}],[indeks|int{0}:val|streng(1){c}]: endSelfMadeDataFormat */ $xml -> show (); /* <?xml version="1.1" encoding="UTF-8" ?><root><a>b</a><0>c</0></root> */ $json -> vis ( ); /* {"a":"b","0":"c"} */

CoffeeScript-eksempel

Kildetekst på CoffeeScript- sprog # Implementatorklasse IStorage get : (nøgle) -> sæt : (nøgle, værdi) -> # ConcreteImplementor klasse IFlashStorage udvider IStorage # ... # ConcreteImplementor klasse IJavaStorage udvider ISstorage # ... # ConcreteImplementor klasse ISessionStorage udvider IStorage # ... # ConcreteImplementor klasse ICookieStorage udvider ISstorage # ... # ConcreteImplementor klasse IGhostStorage udvider IStorage # ... # Abstraktionsklasse AStorage # protected _implementer : if sessionStorage ny ISessionStorage else if navigator . plugins [ "Shockwave Flash" ] ny IFlashStorage else if navigator . javaEnabled () ny IJavaStorage else if navigator . cookieEnabled ny ICookieStorage ellers ny IGhostStorage # offentlig indlæsning : (nøgle) -> glemte : (nøgle) -> gem : (nøgle, værdi) -> # RefinedAbstraction klasse InfoStorage udvider ASlagerbelastning : (nøgle) -> @_implementer . ( "Info: #{ key } " ) gem : (nøgle, værdi) -> @_implementer . sæt ( "Info: #{ nøgle } " , værdi ) glemte : (nøgle) -> @_implementer . sæt ( "Info: #{ key } " , null )

JavaScript-eksempel

JavaScript kildekode // Implementor ("grænseflade") funktion Implementor () { this . operation = funktion () {}; } // ConcreteImplementor (Implementation Implementor) funktion ConcreteImplementorA () { this . operation = function () { alert ( "ConcreteImplementorA.operation" ); }; } ConcreteImplementorA . prototype = Objekt . skabe ( Implementor . prototype ); BetonImplementorA . prototype . constructor = ConcreteImplementorA ; function ConcreteImplementorB () { this . operation = function () { advarsel ( "ConcreteImplementorB.operation" ); }; } ConcreteImplementorB . prototype = Objekt . skabe ( Implementor . prototype ); BetonImplementorB . prototype . constructor = ConcreteImplementorB ; // Abstraktionsfunktion Abstraktion ( ) { var implementor ; dette . getImplementor = function () { // adgang til implementoren fra RefinedAbstraction return implementor ; }; dette . setImplementor = funktion ( val ) { implementor = val ; }; dette . operation = funktion () { implementor . operation (); }; } // RefinedAbstraction- funktion RefinedAbstraction () { var abstr = new Abstraction (); dette . setImplementor = funktion ( val ) { abstr . setImplementor ( val ); }; dette . operation = funktion () { abstr . operation (); }; } // usage: var refAbstr = new RefinedAbstraction (); refAbstr . setImplementor ( ny ConcreteImplementorA () ); refAbstr . operation (); // "BetonImplementorA. operation" refAbstr . setImplementor ( ny ConcreteImplementorB () ); refAbstr . operation (); // "BetonImplementorB. operation"

Uden behovet for at overbelaste abstraktionsmetoder kan RefinedAbstraction forenkles meget:

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

Du kan også gemme referencer til overbelastede metoder umiddelbart efter at abstraktionen er instantieret:

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

VB.NET eksempel

Kildetekst på VB.NET sprog navnerumsbro _ ' Program - Test Application Class Program Shared Sub Main () Dim AB As Abstraction = New RefinedAbstraction () ' Installer implementering og ring til AB . Implementor = New ConcreteImplementorA () AB . operation () ' Installer implementering og ring til AB . Implementor = New ConcreteImplementorB () AB . operation () ' Vent på brugerhandlingskonsol . Læs () End Sub End Class ''' <summary> ''' Abstraktion - abstraktion ''' </summary> ''' <remarks> ''' <li> ''' <lu>definer abstraktionsgrænsefladen;</lu> ''' < lu >gemmer en reference til et objekt <see cref="Implementor"/></lu> ''' </li> ''' </remarks > Klasseabstraktion beskyttet m_implementor Som Implementor ' Public Property Implementor () Som Implementor Get Return m_implementor End Get Sæt ( ByVal value As Implementor ) m_implementor = værdi End Set End Property Offentlig tilsidesættelig underoperation ( ) m_implementor . Operation () End Sub End Class ''' <summary> ''' Implementer ''' </summary> ''' <remarks> ''' <li> ''' <lu> definerer en grænseflade for implementeringsklasser. Det behøver ikke nøjagtigt at ''' matche klassegrænsefladen <see cref="Abstraction"/>. Faktisk kan begge '''-grænseflader være helt forskellige. Normalt repræsenterer klassegrænsefladen ''' <see cref="Implementor"/> kun primitive operationer, og klassen ''' <see cref="Abstraction"/> definerer operationer på højere niveau baseret på disse primitiver ''';< / lu> ''' </li> ''' </remarks> MustInherit Class Implementor Public MustOverride Sub Operation () End Class ''' <summary> ''' RefinedAbstraction - en raffineret abstraktion ''' </summary> ''' <remarks> ''' <li> ''' <lu> udvider grænsefladen defineret af abstraktionen <see cref= "Abstraktion" /></lu> ''' </li> ''' </remarks> Klasse raffineret Abstraktion arver abstraktion Public Overrides Sub Operation () implementer . Operation () End Sub End Class ''' <summary> ''' ConcreteImplementor - en konkret implementer ''' </summary> ''' <remarks> ''' <li> ''' <lu>indeholder en konkret implementering af grænsefladen <see cref= "Implementor"/ ></lu> ''' </li> ''' </remarks> Klasse ConcreteImplementorA arver Implementor Offentlige tilsidesættelser Sub Operation () Konsol . WriteLine ( "ConcreteImplementorA Operation" ) End Sub End Class ' "ConcreteImplementorB" Klasse ConcreteImplementorB arver Implementor Offentlige tilsidesættelser Sub Operation () Konsol . WriteLine ( "ConcreteImplementorB Operation" ) End Sub End Class End Namespace

Python-eksempel

Kildekode i Python # Implementor klasse DrawingAPI : def drawCircle ( selv , x , y , radius ): bestået # ConcreteImplementor 1/2 klasse DrawingAPI1 ( DrawingAPI ): def drawCircle ( self , x , y , radius ): print "API1.circle at %f : %f radius %f " % ( x , y , radius ) # ConcreteImplementor 2/2 klasse DrawingAPI2 ( DrawingAPI ): def drawCircle ( self , x , y , radius ): print "API2.circle at %f : %f radius %f " % ( x , y , radius ) # Abstraktionsklasse Form : # Def draw lavt niveau ( selv ): bestået # Def resizeByPercentage på højt niveau ( selv , pct ): bestået # Raffineret abstraktionsklasse CircleShape ( Shape ): def __init__ ( self , x , y , radius , drawingAPI ) : self . __x = x selv . __y = y selv . __radius = radius selv . __drawingAPI = drawingAPI # lavt niveau dvs. Implementeringsspecifik def draw ( self ): selv . __drawingAPI . tegneCirkel ( selv . __x , selv . __y , selv . __radius ) # højt niveau, dvs. abstraktionsspecifik def resizeByPercentage ( selv , pct ): selv . __radius *= pct def main (): shapes = [ CircleShape ( 1 , 2 , 3 , DrawingAPI1 ()), CircleShape ( 5 , 7 , 11 , DrawingAPI2 ()) ] for form i former : form . resizeByPercentage ( 2,5 ) form . tegne () if __name__ == "__main__" : main ()

Litteratur

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

Links