ブリッジの設計パターンを理解する


24

「ブリッジ」デザインパターンがまったくわかりません。さまざまなWebサイトを調べましたが、助けにはなりませんでした。

誰でもこれを理解するのに役立つことができますか?


2
私もそれを理解していません。答えを見るのを楽しみにしています:)
バイオレットジラフ

設計パターンを説明する多くのWebサイトや書籍があります。すでに書かれていることを繰り返すことに価値はないと思います。特定の質問をすることができます。それを理解するのにも時間がかかり、異なるソースとサンプルを切り替え続けました。
ヘレナ

回答:


16

OOPではポリモーフィズムを使用するため、抽象化には複数の実装を含めることができます。次の例を見てみましょう。

//trains abstraction
public interface Train
{ 
    move();
}
public class MonoRail:Train
{
    public override move()
    {
        //use one track;
    }
}
public class Rail:Train
{
    public override move()
    {
        //use two tracks;
    }
}

新しい要件が導入され、列車の加速の観点を取り入れる必要があるため、以下のようにコードを変更します。

    public interface Train
    { 
        void move();
    }
    public class MonoRail:Train
    {
        public override void move()
        {
            //use one track;
        }
    }
    public class ElectricMonoRail:MonoRail
    {
        public override void move()
        {
            //use electric engine on one track.
        }
    }
    public class DieselMonoRail: MonoRail
    {
        public override void move()
        {
            //use diesel engine on one track.
        }
    }
    public class Rail:Train
    {
        public override void move()
        {
            //use two tracks;
        }
    }
    public class ElectricRail:Rail
    {
        public override void move()
        {
            //use electric engine on two tracks.
        }
    }
    public class DieselRail: Rail
    {
        public override void move()
        {
            //use diesel engine on two tracks.
        }
    }

上記のコードは保守可能ではなく、再利用性に欠けています(同じトラックプラットフォームでアクセラレーションメカニズムを再利用できると仮定した場合)。次のコードは、ブリッジパターンを適用し、2つの異なる抽象化、トレイントランスポート加速を分離します。

public interface Train
{ 
    void move(Accelerable engine);
}
public interface Accelerable
{
    public void accelerate();
}
public class MonoRail:Train
{
    public override void move(Accelerable engine)
    {
        //use one track;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class Rail:Train
{
    public override void move(Accelerable engine)
    {
        //use two tracks;
        engine.accelerate(); //engine is pluggable (runtime dynamic)
    }
}
public class ElectricEngine:Accelerable{/*implementation code for accelerable*/}
public class DieselEngine:Accelerable{/*implementation code for accelerable*/}

3
とてもいい例です。私は私の2セントを追加します。これは相続上の組成を好むのは非常に良い例です
zzfima

1
それが価値があるものについては、それMonorailは実際には2つの単語ではなく、単一の(複合)単語であるためだと思います。MonoRailは、異なる種類のレールではなく、Railのサブクラスになります(これは)。私たちが使用しないことと同じようにSunShine、またはCupCake、彼らは次のようになりますSunshineCupcake
ErikE

この行「2つの異なる抽象化、列車の輸送と加速」は、2つの階層とは何かを指摘し、それらを独立して変化させることを解決しようとしています。
wangdq

11

ほとんどのデザインパターンには役立つ名前がありますが、「ブリッジ」という名前は、その機能に関して直感的ではないことがわかります。

概念的には、クラス階層で使用される実装の詳細を、通常は独自の階層を持つ別のオブジェクトにプッシュします。そうすることで、これらの実装の詳細への密接な依存関係を取り除き、その実装の詳細を変更できるようにします。

小規模では、これを、新しい動作をプラグインできる方法での戦略パターンの使用に例えます。しかし、戦略でよく見られるようにアルゴリズムを単にラップする代わりに、実装オブジェクトは通常、より多くの機能で満たされています。そして、この概念をクラス階層全体に適用すると、大きなパターンがブリッジになります。(繰り返しますが、名前は嫌いです)。

毎日使用するパターンではありませんが、多重継承の(見かけ上の)必要性がある場合に発生する可能性のあるクラスの爆発的な増加を管理する際に役立つことがわかりました。

これが実際の例です。

デザインサーフェイスにコントロールをドロップして構成できるRADツールがあるので、次のようなオブジェクトモデルがあります。

Widget // base class with design surface plumbing
+ Top
+ Left
+ Width
+ Height
+ Name
+ SendToBack
+ BringToFront
+ OnPropertyEdit
+ OnSelect
+ Validate
+ ShowEditor
+ Paint
+ Etc

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor // override base to show a property editor form specific to a Textbox
+ Paint // override to render a textbox onto the surface    
+ Etc

ListWidget : Widget // list specific
+ Items
+ SelectedItem
+ ShowEditor // override base to show a property editor form specific to a List
+ Paint // override to render a list onto the surface
+ Etc

など、おそらく12個のコントロールがあります。

ただし、その後、複数のテーマ(ルックアンドフィール)をサポートするための新しい要件が追加されます。我々は以下のテーマを持っているとしましょう: Win32WinCEWinPPCWinMo50WinMo65。各テーマには、DefaultFont、DefaultBackColor、BorderWidth、DrawFrame、DrawScrollThumbなどのレンダリング関連の操作のための異なる値または実装があります。

次のようなオブジェクトモデルを作成できます。

Win32TextboxWidget : TextboxWidget

Win32ListWidget : ListWidget

など、1つの制御タイプ用

WinCETextboxWidget : TextboxWidget

WinCEListWidget : ListWidget

など、他のコントロールタイプごと(再度)

アイデアが得られます。ウィジェット数とテーマ数のクラスが爆発的に増えます。これにより、RADデザイナーは、すべてのテーマを認識するようになり、複雑になります。さらに、新しいテーマを追加すると、RADデザイナーが強制的に変更されます。さらに、テーマ内には多くの一般的な実装があり、それを継承することは素晴らしいことですが、コントロールはすでに共通のベース(Widget)から継承しています。

その代わり、私がやったのは、テーマを実装する別のオブジェクト階層を作成することです。各ウィジェットは、レンダリング操作を実装するオブジェクトへの参照を保持します。多くのテキストでは、このクラスに接尾辞が付いていますImplが、その命名規則から外れています。

だから今私のTextboxWidgetようになります:

TextboxWidget : Widget // text box specific
+ Text
+ MaxLength
+ Font
+ ShowEditor
+ Painter // reference to the implementation of the widget rendering operations
+ Etc

また、さまざまな画家にテーマ固有のベースを継承させることができますが、これは以前はできませんでした。

Win32WidgetPainter
+ DefaultFont
+ DefaultFontSize
+ DefaultColors
+ DrawFrame
+ Etc

Win32TextboxPainter : Win32WidgetPainter

Win32ListPainter : Win32WidgetPainter

良い点の1つは、実行時に実装を動的にロードできることです。これにより、コアソフトウェアを変更せずに、必要な数のテーマを追加できます。言い換えれば、「実装は抽象化とは無関係に変化する可能性があります」。


これがどのように橋のパターンになると思われるのか分かりませんか?ウィジェット階層に新しいコンポーネントを追加すると、その新しいウィジェットをすべてのペインタ(Win32NewWidgetPainter、PPCNewWidgetPainter)に追加する必要があります。これは、独立して成長する2つの階層ではありません。適切なブリッジパターンの場合、各ウィジェットのPlatformWidgetPainterクラスをサブクラス化せず、ウィジェットの「記述子の描画」を受け取ります。
マジョッド

フィードバックをありがとう、あなたは正しい。私がこれを投稿したのは数年前でしたが、今レビューすると、私が導き出した最後のビットまでブリッジについてよく説明 しています。あなたは可能な実装側の継承ツリーを持っているが、それは(おそらくより汎用的であるべき、と、必要に応じて上書きされ、必要な基本操作を含みます)。これは、この例の基にした実際のコードに近いものです。Win32TextboxPainterWin32ListPainterWin32WidgetPainterStaticStyleControlPainterEditStyleControlPainterButtonStyleControlPainter
tcarvin

3

ブリッジは、具体的な実装から抽象化を分離することを意図しているため、両方が独立して変化する可能性があります。

  • サブクラス化で抽象化を洗練する
  • 抽象化もその洗練も知らなくても、サブクラス化によって異なる実装を提供します。
  • 必要に応じて、実行時に最適な実装を選択します。

ブリッジは構成を使用してこれを実現します。

  • 抽象化は、実装オブジェクトを参照(参照またはポインター)します
  • 抽象化とその改良は、実装インターフェースのみを知っていた

ここに画像の説明を入力してください

頻繁な混乱に関する追加の発言

このパターンは、アダプターパターンに非常に似ています。抽象化は、実装に異なるインターフェイスを提供し、そのために構成を使用します。しかし:

これらのパターンの主な違いは、その意図にあります-Gamma
&al、デザインパターン、再利用可能なオブジェクト指向ソフトウェアの要素、1995

このデザインパターンに関する優れた独創的な本では、著者も次のことを観察しています。

  • アダプターは、非互換性が検出され、カップリングが予期しない場合によく使用されます
  • ブリッジは、クラスが独立して進化することが予想される設計の最初から使用されます。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.