ブリッジパターンは、ソフトウェアエンジニアリングで使用される設計パターンであり、 「抽象化をその実装から分離して、2つが独立して変化できるようにする」ことを目的としており、 Gang of Fourによって導入されました。[1]ブリッジはカプセル化と集約を使用し、継承を使用して責任を異なるクラスに分離することができます。
クラスが頻繁に変更される場合、プログラムに関する事前知識がほとんどなくてもプログラムコードを簡単に変更できるため、オブジェクト指向プログラミングの機能は非常に役立ちます。ブリッジパターンは、クラスとその動作の両方が頻繁に変更される場合に役立ちます。クラス自体は抽象化、クラスで実行できることは実装と考えることができます。ブリッジ パターンは、2 つの抽象化レイヤーと考えることもできます。
固定された実装が 1 つしかない場合、このパターンはC++ の世界ではPimplイディオムとして知られています。
ブリッジ パターンはアダプタ パターンと混同されることが多く、オブジェクト アダプタ パターンを使用して実装されることがよくあります。たとえば、以下の Java コードがその例です。
バリエーション: 実装の存在を抽象化が利用される時点まで延期することで、実装をさらに分離することができます。
概要
Bridge設計パターンは、柔軟で再利用可能なオブジェクト指向ソフトウェア、つまり実装、変更、テスト、再利用が容易なオブジェクトを設計するために、繰り返し発生する設計上の問題を解決する方法を記述した、よく知られている23のGoF設計パターンの1つです。[1]
Bridgeデザインパターンはどのような問題を解決できるでしょうか? [2]
- 抽象化とその実装は、互いに独立して定義および拡張される必要があります。
- 実行時に実装を選択できるように、抽象化とその実装間のコンパイル時のバインディングは避ける必要があります。
サブクラス化を使用する場合、異なるサブクラスは異なる方法で抽象クラスを実装します。ただし、実装はコンパイル時に抽象化にバインドされ、実行時に変更することはできません。
Bridge デザイン パターンはどのようなソリューションを説明していますか?
- 抽象化 (
Abstraction) とその実装 (Implementor) を別々のクラス階層に配置することで分離します。 Abstractionオブジェクトに関して(委任することによって)を実装しますImplementor。
これにより、実行時にオブジェクトを構成できるようになります。
Abstraction以下の統一モデリング言語クラスとシーケンス図
も参照してください。Implementor
構造
UML クラス図とシーケンス図

上記の統一モデリング言語クラス図では、抽象化 ( Abstraction) は通常のように単一の継承階層に実装されていません。 代わりに、抽象化 ( ) 用の 1 つの階層Abstractionとその実装 ( ) 用の別の階層があり、これら 2 つがImplementor互いに独立しています。 インターフェースAbstraction( ) は、インターフェース ( )
operation()に関して (に委任することによって) 実装されます。
UMLシーケンス図は、
実行時の相互作用を示しています。オブジェクトは、 (を呼び出すことによって) オブジェクトに実装を委任し、オブジェクトは操作を実行して に戻ります。
Implementorimp.operationImp()
Abstraction1Implementor1operationImp()Implementor1Abstraction1
クラス図
- 抽象化(抽象クラス)
- 抽象インターフェースを定義する
- 実装者参照を維持します。
- RefinedAbstraction(通常クラス)
- 抽象化によって定義されたインターフェースを拡張する
- 実装者(インターフェース)
- 実装クラスのインターフェースを定義する
- ConcreteImplementor (通常のクラス)
- Implementorインターフェースを実装する

例
C#
ブリッジパターンは、オブジェクトをツリー構造で構成します。抽象化と実装を切り離します。ここで、抽象化は、オブジェクトが呼び出されるクライアントを表します。C# で実装された例を以下に示します。
// 真に分離されたアーキテクチャを提供するのに役立ちます
public interface IBridge { void Function1 (); void Function2 (); }
パブリッククラスBridge1 : IBridge {パブリックvoid Function1 () { Console.WriteLine ( "Bridge1.Function1 " ) ; }
パブリックvoid Function2 () { Console.WriteLine ( "Bridge1.Function2 " ) ; } }
パブリッククラスBridge2 : IBridge {パブリックvoid Function1 ( ) { Console.WriteLine ( "Bridge2.Function1" ) ; }
パブリックvoid Function2 () { Console.WriteLine ( "Bridge2.Function2 " ) ; } }
パブリックインターフェイスIAbstractBridge { void CallMethod1 (); void CallMethod2 (); }
パブリッククラスAbstractBridge : IAbstractBridge {パブリックIBridgeブリッジ;
パブリックAbstractBridge ( IBridgeブリッジ) { this .bridge = bridge ; }
パブリックvoid CallMethod1 () { this . bridge . Function1 (); }
パブリックvoid CallMethod2 () { this . bridge . Function2 (); } }
Bridge クラスは、同じインターフェイス指向アーキテクチャを使用してオブジェクトを作成する実装です。一方、抽象化は実装クラスのインスタンスを取得し、そのメソッドを実行します。したがって、これらは互いに完全に分離されています。
結晶
抽象クラスDrawingAPI abstract def draw_circle ( x : Float64 , y : Float64 , radius : Float64 )終了
クラスDrawingAPI1 < DrawingAPI def draw_circle ( x : Float , y : Float , radius : Float ) "API1.circle at #{ x } : #{ y } - radius: #{ radius } " end end
クラスDrawingAPI2 < DrawingAPI def draw_circle ( x : Float64 , y : Float64 , radius : Float64 ) "API2.circle at #{ x } : #{ y } - radius: #{ radius } " end end
抽象クラスShape保護されたゲッターdrawing_api : DrawingAPI
def初期化( @drawing_api )終了
抽象定義描画抽象定義resize_by_percentage (パーセント: Float64 )終了
クラスCircleShape < Shapeゲッターx : Float64ゲッターy : Float64ゲッター半径: Float64
def初期化( @x 、@y 、@radius 、drawing_api : DrawingAPI ) super ( drawing_api )終了
def draw @drawing_api . draw_circle ( @x , @y , @radius )終了
def resize_by_percentage (パーセント: Float64 ) @radius *= ( 1 +パーセント/ 100 )終了終了
クラスBridgePattern def self.test shapes = [ ] of Shape shapes << CircleShape.new ( 1.0 , 2.0 , 3.0 , DrawingAPI1.new ) shapes << CircleShape.new ( 5.0 , 7.0 , 11.0 , DrawingAPI2.new )
shapes.each do | shape | shape.resize_by_percentage ( 2.5 )はshape.drawを実行しますend end end
BridgePattern .テスト
出力
API1.circle 1.0:2.0 - 半径: 3.075 API2.circle 5.0:7.0 - 半径: 11.275
C++
#include <iostream> #include <文字列> #include <ベクター>
クラスDrawingAPI { public : virtual ~ DrawingAPI () = default ; virtual std :: string DrawCircle ( float x 、float y 、float radius ) const = 0 ; };
クラスDrawingAPI01 : public DrawingAPI { public : std :: stringDrawCircle ( floatx 、floaty 、floatradius ) const override { return " API01.circle at " + std :: to_string ( x ) + ":" + std :: to_string ( y ) + " - radius : " + std :: to_string ( radius ) ; } };
クラスDrawingAPI02 : public DrawingAPI { public : std :: stringDrawCircle ( floatx 、floaty 、floatradius ) const override { return " API02.circle at " + std :: to_string ( x ) + " :" + std :: to_string ( y ) + " - radius: " + std :: to_string ( radius ) ; } };
クラスShape { public : Shape ( const DrawingAPI & drawing_api ) : drawing_api_ ( drawing_api ) {}仮想~ Shape () = default ;
virtual std :: string Draw () const = 0 ; virtual float ResizeByPercentage ( const float percent ) = 0 ;
保護されています:
const DrawingAPI & drawing_api_ ; };
クラスCircleShape : public Shape { public : CircleShape ( float x , float y , float radius , const DrawingAPI & drawing_api ) : Shape ( drawing_api ), x_ ( x ), y_ ( y ), radius_ (半径) {}
std :: string Draw () const override { return drawing_api_ . DrawCircle ( x_ , y_ , radius_ ); }
float ResizeByPercentage ( const float percent ) override { return radius_ *= ( 1.0f + percent / 100.0f ); } private : float x_ , y_ , radius_ ; };
int main ( int argc 、char ** argv ) { const DrawingAPI01 api1 {}; const DrawingAPI02 api2 {}; std :: vector < CircleShape > shapes { CircleShape { 1.0f 、2.0f 、3.0f 、api1 }、CircleShape { 5.0f 、7.0f 、11.0f 、api2 } };
for ( auto & shape : shapes ) { shape . ResizeByPercentage ( 2.5 ); std :: cout << shape . Draw () << std :: endl ; }
0 を返す; }
出力:
API01.circle 1.000000:2.000000 - 半径: 3.075000 API02.circle 5.000000:7.000000 - 半径: 11.275000
ジャワ
次のJavaプログラムは、口座操作とこれらの操作のログ記録を分離する銀行口座を定義します。
// Logger には、info と warning の 2 つの実装があります。
@FunctionalInterface
interface Logger { void log ( String message ); static Logger info () { return message -> System . out . println ( "info: " + message ); } static Logger warning () { return message -> System . out . println ( "warning: " + message ); } }
abstract class AbstractAccount { private Logger logger = Logger . info (); public void setLogger ( Logger logger ) { this . logger = logger ; } // ログ記録部分は Logger 実装に委譲されますprotected void operatie ( String message , boolean result ) { logger . log ( message + " result " + result ); } }
クラス SimpleAccount はAbstractAccount を拡張します{ private int balance ; public SimpleAccount ( int balance ) { this . balance = balance ; } public boolean isBalanceLow () { return balance < 50 ; } public void withdraw ( int amount ) { boolean shouldPerform = balance >= amount ; if ( shouldPerform ) { balance -= amount ; } operated ( "withdraw " + amount , shouldPerform ); } }
public class BridgeDemo { public static void main ( String [] args ) { SimpleAccount account = new SimpleAccount ( 100 ); account . withdraw ( 75 ); if ( account . isBalanceLow ()) { // 実行時に Logger 実装を変更することもできますaccount . setLogger ( Logger . warning () ); } account . withdraw ( 10 ); account . withdraw ( 100 ); } }
出力は次のようになります:
情報: 撤回 75 結果 true 警告: 撤回 10 結果 true 警告: 撤回 100 結果 false
PHP の
インターフェース DrawingAPI
{
関数 drawCircle ( $x , $y , $radius );
}
クラス DrawingAPI1 は DrawingAPIを実装します { public function drawCircle ( $x , $y , $radius ) { echo "API1.circle at $x : $y radius $radius . \n " ; } }
クラス DrawingAPI2 は DrawingAPIを実装します { public function drawCircle ( $x , $y , $radius ) { echo "API2.circle at $x : $y radius $radius . \n " ; } }
抽象 クラス Shape
{
protected $drawingAPI ;
パブリック 抽象 関数 draw ();
パブリック 抽象 関数 resizeByPercentage ( $pct );
保護された 関数 __construct ( DrawingAPI $drawingAPI )
{
$this -> drawingAPI = $drawingAPI ;
}
}
クラス CircleShape は Shapeを拡張します { private $x ; private $y ; private $radius ;
パブリック 関数 __construct ( $x 、 $y 、 $radius 、 DrawingAPI $drawingAPI )
{
親:: __construct ( $drawingAPI );
$this -> x = $x ;
$this -> y = $y ;
$this -> radius = $radius ;
}
パブリック 関数 draw ()
{
$this- > drawingAPI- > drawCircle ($this- > x 、 $this- > y 、 $this- > radius );
}
パブリック 関数 resizeByPercentage ( $pct )
{
$this -> radius *= $pct ;
}
}
クラス Tester
{
public static function main ()
{
$shapes = array (
new CircleShape ( 1 、 3 、 7 、 new DrawingAPI1 ()),
new CircleShape ( 5 、 7 、 11 、 new DrawingAPI2 ()),
);
foreach ( $shapesを $shapeとして ) { $shape -> resizeByPercentage ( 2.5 ); $shape -> draw (); } } }
テスター:: main ();
出力:
API1.1:3 半径 17.5 の円 API2.円 5:7 半径 27.5
スカラ
特性DrawingAPI { def drawCircle ( x : Double 、y : Double 、radius : Double ) }
クラスDrawingAPI1 はDrawingAPIを拡張します{ def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #1 $ x $ y $ radius " ) }
クラスDrawingAPI2 はDrawingAPIを拡張します{ def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #2 $ x $ y $ radius " ) }
抽象クラスShape ( drawingAPI : DrawingAPI ) { def draw () def resizePercentage ( pct : Double ) }
クラスCircleShape ( x : Double 、y : Double 、var radius : Double 、drawingAPI : DrawingAPI )はShape ( drawingAPI : DrawingAPI )を拡張します{
def draw ( ) = drawingAPI.drawCircle ( x , y ,半径)
def resizePercentage ( pct : Double ) {半径*= pct } }
オブジェクトBridgePattern { def main ( args : Array [ String ]) { Seq ( new CircleShape ( 1 , 3 , 5 , new DrawingAPI1 ), new CircleShape ( 4 , 5 , 6 , new DrawingAPI2 ) ) foreach { x => x . resizePercentage ( 3 ) x . draw () } } }
パイソン
"""
ブリッジパターンの例。
"""
from abc import ABCMeta , abstractmethod
NOT_IMPLEMENTED = "これを実装する必要があります。"
クラス DrawingAPI :
__metaclass__ = ABCMeta
@abstractmethod
def draw_circle ( self 、 x 、 y 、 radius ):
NotImplementedError ( NOT_IMPLEMENTED )を発生させます
クラス DrawingAPI1 ( DrawingAPI ):
def draw_circle ( self , x , y , radius ):
return f "API1.circle at { x } : { y } - radius: { radius } "
クラス DrawingAPI2 ( DrawingAPI ):
def draw_circle ( self , x , y , radius ):
return f "API2.circle at { x } : { y } - radius: { radius } "
クラス DrawingAPI3 ( DrawingAPI ):
def draw_circle ( self , x , y , radius ):
return f "API3.circle at { x } : { y } - radius: { radius } "
クラス Shape :
__metaclass__ = ABCMeta
drawing_api = None
def __init__ ( self 、 drawing_api ):
self . drawing_api = drawing_api
@abstractmethod
def draw ( self ):
NotImplementedError ( NOT_IMPLEMENTED )を発生させます
@abstractmethod
resize_by_percentageを定義します ( self 、percent ): NotImplementedErrorを発生させます( NOT_IMPLEMENTED )
クラス CircleShape ( Shape ):
def __init__ ( self , x , y , radius , drawing_api ):
self . x = x
self . y = y
self . radius = radius
super ( CircleShape , self ) . __init__ ( drawing_api )
def draw ( self ) :
self.drawing_api.draw_circle ( self.x , self.y , self.radius )を返し ます。
def resize_by_percentage ( self , percent ):
self . radius *= 1 + percent / 100
クラス BridgePattern :
@staticmethod
def test ():
shapes = [
CircleShape ( 1.0 , 2.0 , 3.0 , DrawingAPI1 ()),
CircleShape ( 5.0 , 7.0 , 11.0 , DrawingAPI2 ()),
CircleShape ( 5.0 , 4.0 , 12.0 , DrawingAPI3 ()),
]
shapes内のshape の場合: shape.resize_by_percentage ( 2.5 ) print ( shape.draw ( ) )
BridgePattern.test ( )の
参照
参考文献
- ^ ab ガンマ、エリック、ヘルム、リチャード、ジョンソン、ラルフ、ブリサイドス、ジョン(1994)。デザインパターン: 再利用可能なオブジェクト指向ソフトウェアの要素。Addison-Wesley。p. 151。ISBN 0-201-63361-2。
- ^ 「Bridge デザイン パターン - 問題、解決策、適用性」。w3sDesign.com。2017年8 月 12 日閲覧。
- ^ 「Bridge デザイン パターン - 構造とコラボレーション」。w3sDesign.com。2017年8 月 12 日閲覧。
