ブリッジとアダプターのパターンの違いは何ですか?
ブリッジとアダプターのパターンの違いは何ですか?
回答:
「アダプターは、設計された後に機能します。ブリッジは、機能する前に機能します。[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
http://en.wikipedia.org/wiki/Adapter_pattern
Adapterパターンは、既存のコードを新しいシステムまたはインターフェースで機能させることを目的としています。
別のアプリケーションの既存の拡張性インターフェースに提供したい企業標準のWebサービスAPIのセットがある場合は、これを行うためのアダプターのセットを作成することを検討してください。灰色の領域があり、ファサードのような他のパターンも同様であるため、パターンの技術的な定義方法についての詳細です。
http://en.wikipedia.org/wiki/Bridge_pattern
Bridgeパターンは、アルゴリズムまたはシステムの代替実装を可能にする予定です。
古典的なBridgeパターンの例ではありませんが、データストアの実装がいくつかある場合を想像してみてください。1つはスペースで効率的で、もう1つは生のパフォーマンスで効率的です...そして、アプリまたはフレームワークの両方で提供するビジネスケースがあります。 。
あなたの質問に関して、「どこでどのパターンを使用できるか」という答えは、プロジェクトにとって意味のある場所ならどこにでもあります。おそらく、どちらか一方を使用する必要があると思われる場所についての議論を導くために、明確な編集を提供することを検討してください。
アダプタ:
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);
}
}
ブリッジ:
編集:(@quasoftの提案に従って)
このパターンには4つのコンポーネントがあります。
抽象化:インターフェースを定義します
RefinedAbstraction:抽象化を実装します:
実装者:実装のためのインターフェースを定義します
ConcreteImplementor:Implementorインターフェースを実装します。
コードスニペット:
Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();
gear = new AutoGear();
vehicle = new Car(gear);
vehicle.addGear();
関連記事:
いつブリッジパターンを使用しますか?アダプターパターンとどう違うのですか?
主な違い:ソースメイキング記事から
この投稿はかなり前からあります。ただし、ファサードはアダプターにいくらか似ていますが、まったく同じではないことを理解することが重要です。アダプタは、既存のクラスを通常は互換性のないクライアントクラスに「適合」させます。アプリケーションがクライアントとして使用している古いワークフローシステムがあるとします。あなたの会社は、ワークフローシステムを新しい(互換性のない)ワークフローシステム(インターフェイスに関して)に置き換える可能性があります。ほとんどの場合、アダプターパターンを使用して、新しいワークフローエンジンのインターフェイスを実際に呼び出すコードを記述できます。ブリッジは通常、別の方法で使用されます。実際に異なるファイルシステム(つまり、ローカルディスク、NFSなど)で動作する必要があるシステムがある場合は、ブリッジパターンを使用して、すべてのファイルシステムで動作する1つの抽象化レイヤーを作成できます。これは基本的に、ブリッジパターンの簡単な使用例です。ファサードとアダプターはいくつかのプロパティを共有しますが、ファサードは通常、既存のインターフェース/クラスを簡素化するために使用されます。EJBの初期の頃は、EJBのローカル呼び出しはありませんでした。開発者は常にスタブを取得し、それを絞り込んで「疑似リモート」と呼びました。これにより、しばしばパフォーマンスの問題が発生しました(特に、実際にネットワーク経由で呼び出された場合)。経験豊富な開発者は、ファサードパターンを使用して、クライアントに非常に粗いインターフェイスを提供します。次に、このファサードは、さらに細かいさまざまなメソッドに対して複数の呼び出しを行います。全体として、これにより、必要なメソッド呼び出しの数が大幅に削減され、パフォーマンスが向上しました。
ブリッジは、改良されたアダプタです。ブリッジにはアダプターが含まれており、アダプターに柔軟性を追加します。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
上位の回答で、@ Jamesは219ページのGoFの文を引用しています。ここで完全な説明を再現する価値があると思います。
アダプターとブリッジ
アダプターとブリッジのパターンには、いくつかの共通の属性があります。どちらも、別のオブジェクトへの間接参照のレベルを提供することで柔軟性を高めます。どちらも、そのオブジェクト以外のインターフェースからこのオブジェクトにリクエストを転送する必要があります。
これらのパターンの主な違いは、その意図にあります。アダプターは、2つの既存のインターフェース間の非互換性の解決に重点を置いています。それはそれらのインターフェースがどのように実装されるかに焦点を合わせておらず、それらがどのように独立して進化するかについても考慮していません。これは、独立して設計された2つのクラスを、どちらか一方を再実装せずに連携させる方法です。一方、ブリッジは、抽象化とその(潜在的に多数の)実装をブリッジします。それはそれを実装するクラスを変えることができるとしても、クライアントに安定したインターフェースを提供します。また、システムの進化に伴う新しい実装にも対応します。
これらの違いの結果として、アダプターとブリッジはソフトウェアライフサイクルのさまざまな時点で使用されることがよくあります。通常、コードの複製を回避するために、互換性のない2つのクラスが連携して動作することがわかった場合、アダプターが必要になることがよくあります。カップリングは予期されていません。対照的に、ブリッジのユーザーは、抽象化にはいくつかの実装が必要であり、両方が独立して進化する可能性があることを事前に理解します。アダプターパターンは、設計後に機能するようにします。ブリッジは、それらが動作する前にそれらを動作させます。これは、Adapterがなんらかの方法でBridgeよりも劣っているという意味ではありません。各パターンは異なる問題に対処するだけです。
(ジェネリック/抽象化された)描画機能を備えた抽象Shapeクラスと、Shapeを実装するCircleがあるとします。ブリッジパターンは、実装(Circleで描画)と汎用/抽象化された機能(Shapeクラスで描画)を分離するための双方向の抽象化アプローチです。
それはどういう意味ですか?一見すると、(依存関係の逆転によって)既に作成したもののように聞こえます。そのため、より単純な、またはよりモジュール化されたコードベースを使用することについての心配はありません。しかし、それはその背後にあるより深い哲学です。
私の理解から、現在のシステム(RedCircleやGreenCircleなど)に密接に関連し、単一の機能(colorなど)のみが異なる新しいクラスを追加する必要がある場合、使用パターンの必要性が生じる可能性があります。特に、既存のシステムクラス(CircleまたはShape)が頻繁に変更され、新しく追加されたクラスがこれらの変更の影響を受けないようにする場合は、ブリッジパターンが必要になります。そのため、一般的な描画機能が新しいインターフェースに抽象化され、ShapeやCircleから独立して描画動作を変更できます。