ブリッジパターンとアダプターパターンの違い


125

ブリッジとアダプターのパターンの違いは何ですか?


おそらく、どちらか一方を使用する必要があると思われる場所についての議論を導くために、明確な編集を提供することを検討してください。
ジェフウィルコックス


回答:


173

「アダプターは、設計された後に機能します。ブリッジは、機能する前に機能します。[GoF、p219]」

事実上、Adapterパターンは、サードパーティまたは社内の既存のコードがあるが、制御不能である場合や、必要なインターフェイスに完全に適合するように変更できない場合に役立ちます。たとえば、終末デバイスの細かい配列を制御できるSuperWeaponsArrayがあります。

public class SuperWeaponsArray {
  /*...*/

  public void destroyWorld() {
    for (Weapon w : armedWeapons) {
      w.fire();
    }
  }
}

すごい。武器インターフェースへの変換よりもはるかに前からある核兵器が兵器庫にあることに気づく場合を除きます。しかし、ここでそれが実際に機能するようにしたいので、どうすればよいのでしょうか。

NukeWeaponsAdaptor-Nukeクラスに基づいていますが、Weaponインターフェースをエクスポートします。甘い、今私たちはきっと世界を破壊することができます。それはちょっとしたことのように思えますが、物事はうまくいきます。


ブリッジあなたは二つの直交する階層を持って知っていれば、それはあなたがクラスの非常識な数を取得しないような方法で、インタフェースと実装を分離する方法を提供します-パターンは、あなたが前もって実装ものです。あなたが持っているとしましょう:

MemoryMappedFileおよびDirectReadFileタイプのファイルオブジェクト。さまざまなソース(たぶんLinuxとWindowsの実装など)からファイルを読み取れるようにしたいとします。Bridgeを使用すると、次の問題を回避できます。

MemoryMappedWindowsFile MemoryMappedLinuxFile DirectReadWindowsFile DirectReadLinuxFile


9
反対投票されましたが、より抽象的なコードリストを使用できますか?この例は具体的すぎて混乱を招きます。

36
@omouseは賛成票を投じましたが、サンプルコードは実際にこの答えを正しいものにするものではありません。注意深い読者にとって、パターンを区別し始めるための十分な指針があるので、全体として、それ良い答えです。
Victor Farazdagi 2010年

15
ブリッジパターンの実際のコード例を提供できますか?
Jaime Hablutzel 2013

2
多くの人が私と同じ方法でこの質問にたどり着いたと思います。おそらく2人のパターンのコードをすでに見ていましたが、いくつかの類似点を認識し、2つのパターンを並置することで理解をさらに固めることができることに気付きました。ブリッジに関するWindowsおよびLinux固有のファイルとの巻き付きを回避するのを助ける行は、少なくとも私にとって、ブリッジパターンの「インプリメンター」(dofactory.com/net/bridge-design-pattern)が"アダプタ"。
ヨルダン

3
「アダプターは、設計後に物事を機能させます。ブリッジは、設計する前に物事を機能させます。」私が読んだ本にはまったく明記されていなかったので、両者を区別するのは困難でした。結局のところ、GOFを読むことは努力に値するものだと思います...
Alexander Derck

15

http://en.wikipedia.org/wiki/Adapter_pattern

Adapterパターンは、既存のコードを新しいシステムまたはインターフェースで機能させることを目的としています。

別のアプリケーションの既存の拡張性インターフェースに提供したい企業標準のWebサービスAPIのセットがある場合は、これを行うためのアダプターのセットを作成することを検討してください。灰色の領域があり、ファサードのような他のパターンも同様であるため、パターンの技術的な定義方法についての詳細です。

http://en.wikipedia.org/wiki/Bridge_pattern

Bridgeパターンは、アルゴリズムまたはシステムの代替実装を可能にする予定です。

古典的なBridgeパターンの例ではありませんが、データストアの実装がいくつかある場合を想像してみてください。1つはスペースで効率的で、もう1つは生のパフォーマンスで効率的です...そして、アプリまたはフレームワークの両方で提供するビジネスケースがあります。 。

あなたの質問に関して、「どこでどのパターンを使用できるか」という答えは、プロジェクトにとって意味のある場所ならどこにでもあります。おそらく、どちらか一方を使用する必要があると思われる場所についての議論を導くために、明確な編集を提供することを検討してください。


14

アダプタ:

  1. 構造パターンです
  2. 2つの互換性のないインターフェースで作業すると便利です

UMLダイアグラム:dofactory記事から:

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

ターゲット :クライアントが使用するドメイン固有のインターフェースを定義します。

アダプタ:インターフェースAdapteeをターゲットインターフェースに適合させます。

Adaptee:適応が必要な既存のインターフェースを定義します。

クライアント :Targetインターフェースに準拠したオブジェクトと連携します。

例:

SquareとRectangleは2つの異なる形状であり、それぞれのarea()を取得するには異なるメソッドが必要です。ただし、Squareは一部のプロパティを変換して、Rectangleインターフェイスで動作します。

public class AdapterDemo{
    public static void main(String args[]){
        SquareArea s = new SquareArea(4);
        System.out.println("Square area :"+s.getArea());
    }
}

class RectangleArea {
    public int getArea(int length, int width){
        return length * width;
    }
}

class SquareArea extends RectangleArea {

    int length;
    public SquareArea(int length){
        this.length = length;
    }
    public int getArea(){
        return getArea(length,length);
    }
}

ブリッジ:

  1. 構造パターンです
  2. 抽象化を実装から切り離し、両方を独立して変更できます
  3. 継承の代わりに構成を使用しているため可能です

編集:(@quasoftの提案に従って)

このパターンには4つのコンポーネントがあります。

  1. 抽象化:インターフェースを定義します

  2. RefinedAbstraction:抽象化を実装します:

  3. 実装者実装のためのインターフェースを定義します

  4. ConcreteImplementor:Implementorインターフェースを実装します。

コードスニペット:

Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();

gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();

関連記事:

いつブリッジパターンを使用しますか?アダプターパターンとどう違うのですか?

主な違い:ソースメイキング記事から

  1. アダプターは、設計後に機能します。橋は彼らがそうする前に彼らを働かせます。
  2. Bridgeは、抽象化と実装を個別に変更できるように事前に設計されています。アダプターは、関連のないクラスが一緒に機能するように改良されました。

回答のドキュメントにあるcar / truck / gearの例を含めます。素晴らしい例と類推。
quasoft 2016年

8

この投稿はかなり前からあります。ただし、ファサードはアダプターにいくらか似ていますが、まったく同じではないことを理解することが重要です。アダプタは、既存のクラスを通常は互換性のないクライアントクラスに「適合」させます。アプリケーションがクライアントとして使用している古いワークフローシステムがあるとします。あなたの会社は、ワークフローシステムを新しい(互換性のない)ワークフローシステム(インターフェイスに関して)に置き換える可能性があります。ほとんどの場合、アダプターパターンを使用して、新しいワークフローエンジンのインターフェイスを実際に呼び出すコードを記述できます。ブリッジは通常、別の方法で使用されます。実際に異なるファイルシステム(つまり、ローカルディスク、NFSなど)で動作する必要があるシステムがある場合は、ブリッジパターンを使用して、すべてのファイルシステムで動作する1つの抽象化レイヤーを作成できます。これは基本的に、ブリッジパターンの簡単な使用例です。ファサードとアダプターはいくつかのプロパティを共有しますが、ファサードは通常、既存のインターフェース/クラスを簡素化するために使用されます。EJBの初期の頃は、EJBのローカル呼び出しはありませんでした。開発者は常にスタブを取得し、それを絞り込んで「疑似リモート」と呼びました。これにより、しばしばパフォーマンスの問題が発生しました(特に、実際にネットワーク経由で呼び出された場合)。経験豊富な開発者は、ファサードパターンを使用して、クライアントに非常に粗いインターフェイスを提供します。次に、このファサードは、さらに細かいさまざまなメソッドに対して複数の呼び出しを行います。全体として、これにより、必要なメソッド呼び出しの数が大幅に削減され、パフォーマンスが向上しました。


この質問の範囲外のように見えますが、アダプタとブリッジをファサードに対して重み付けすることは非常に適切です。
コーディ、

1

ブリッジは、改良されたアダプタです。ブリッジにはアダプターが含まれており、アダプターに柔軟性を追加します。Ravindraの回答の要素がパターン間でどのようにマッピングされるかを次に示します。

      Adapter  |    Bridge
    -----------|---------------
    Target     | Abstraction
    -----------|---------------
               | RefinedAbstraction
               |
               |   This element is Bridge specific. If there is a group of 
               |   implementations that share the same logic, the logic can be placed here.
               |   For example, all cars split into two large groups: manual and auto. 
               |   So, there will be two RefinedAbstraction classes.
    -----------|--------------- 
    Adapter    | Implementor
    -----------|---------------
    Adaptee    | ConcreteImplementor

1

上位の回答で、@ Jamesは219ページのGoFの文を引用しています。ここで完全な説明を再現する価値があると思います。

アダプターとブリッジ

アダプターとブリッジのパターンには、いくつかの共通の属性があります。どちらも、別のオブジェクトへの間接参照のレベルを提供することで柔軟性を高めます。どちらも、そのオブジェクト以外のインターフェースからこのオブジェクトにリクエストを転送する必要があります。

これらのパターンの主な違いは、その意図にあります。アダプターは、2つの既存のインターフェース間の非互換性の解決に重点を置いています。それはそれらのインターフェースがどのように実装されるかに焦点を合わせておらず、それらがどのように独立して進化するかについても考慮していません。これは、独立して設計された2つのクラスを、どちらか一方を再実装せずに連携させる方法です。一方、ブリッジは、抽象化とその(潜在的に多数の)実装をブリッジします。それはそれを実装するクラスを変えることができるとしても、クライアントに安定したインターフェースを提供します。また、システムの進化に伴う新しい実装にも対応します。

これらの違いの結果として、アダプターとブリッジはソフトウェアライフサイクルのさまざまな時点で使用されることがよくあります。通常、コードの複製を回避するために、互換性のない2つのクラスが連携して動作することがわかった場合、アダプターが必要になることがよくあります。カップリングは予期されていません。対照的に、ブリッジのユーザーは、抽象化にはいくつかの実装が必要であり、両方が独立して進化する可能性があることを事前に理解します。アダプターパターンは、設計後に機能するようにします。ブリッジは、それらが動作する前にそれらを動作させます。これは、Adapterがなんらかの方法でBridgeよりも劣っているという意味ではありません。各パターンは異なる問題に対処するだけです。


0

(ジェネリック/抽象化された)描画機能を備えた抽象Shapeクラスと、Shapeを実装するCircleがあるとします。ブリッジパターンは、実装(Circleで描画)と汎用/抽象化された機能(Shapeクラスで描画)を分離するための双方向の抽象化アプローチです。

それはどういう意味ですか?一見すると、(依存関係の逆転によって)既に作成したもののように聞こえます。そのため、より単純な、またはよりモジュール化されたコードベースを使用することについての心配はありません。しかし、それはその背後にあるより深い哲学です。

私の理解から、現在のシステム(RedCircleやGreenCircleなど)に密接に関連し、単一の機能(colorなど)のみが異なる新しいクラスを追加する必要がある場合、使用パターンの必要性が生じる可能性があります。特に、既存のシステムクラス(CircleまたはShape)が頻繁に変更され、新しく追加されたクラスがこれらの変更の影響を受けないようにする場合は、ブリッジパターンが必要になります。そのため、一般的な描画機能が新しいインターフェースに抽象化され、ShapeやCircleから独立して描画動作を変更できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.