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 .
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 . få ( "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 på 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