ブリッジパターンと戦略パターンの違いは何ですか?
-
19-08-2019 - |
質問
dofactory 、ウィキペディア、多くのサイトで多くの記事を読みました。 ブリッジパターンと戦略パターンの違いについてはわかりません。
どちらも抽象化をその実装から切り離し、実行時に実装を変更できることを知っています。
しかし、どの状況で戦略を使用すべきか、どの状況でブリッジを使用すべきかはまだわかりません。
解決
セマンティクス。 wikipedia から:
戦略のUMLクラス図 パターンは次の図と同じです ブリッジパターン。ただし、これら2つ デザインパターンは同じではありません 彼らの意図。戦略 パターンは行動を意味し、 ブリッジパターンは構造用です。
コンテキストと 戦略は 抽象化と ブリッジでの実装 パターン。
私が理解しているように、外部ソースから提供できる動作を抽象化するときに戦略パターンを使用し(たとえば、configはプラグインアセンブリの読み込みを指定できます)、ブリッジパターンを使用しています同じ構造を使用して、コードを少し見やすくする場合。実際のコードは非常によく似ています-パターンを適用するのはわずかに異なる理由です。
他のヒント
ブリッジパターンは構造的なパターンです(ソフトウェアコンポーネントをどのように構築しますか?)。戦略パターンは動的パターンです(ソフトウェアで動作を実行する方法を教えてください)。
構文は似ていますが、目標は異なります:
- 戦略:操作を行う方法は他にもあります。戦略を使用すると、実行時にアルゴリズムを選択でき、コンパイル時に多くの副作用なしに単一の戦略を変更できます。
- ブリッジ:インターフェースとクラスの階層を分割し、抽象参照で結合できます(説明)
戦略:
- ストラテジーに関連付けられたコンテキスト:コンテキストクラス(おそらく抽象的ですが、実際にはインターフェイスではありません。実装全体ではなく特定の動作をカプセル化するため)は、ストラテジーインターフェイスリファレンスと実装を知っている/含んでいます。 で戦略動作を呼び出します。
-
意図は、実行時に動作をスワップする機能です
class Context { IStrategy strategyReference; void strategicBehaviour() { strategyReference.behave(); } }
ブリッジ
- 実装に関連付けられていない抽象化:抽象化インターフェイス(または動作抽象のほとんどを含む抽象クラス)は、実装インターフェイスの参照を認識/包含しません
-
意図は、抽象化を実装から完全に切り離すことです
interface IAbstraction { void behaviour1(); ..... } interface IImplementation { void behave1(); void behave2(); ..... } class ConcreteAbstraction1 implements IAbstraction { IImplementation implmentReference; ConcreteAbstraction1() { implmentReference = new ImplementationA() // Some implementation } void behaviour1() { implmentReference.behave1(); } ............. } class ConcreteAbstraction2 implements IAbstraction { IImplementation implmentReference; ConcreteAbstraction1() { implmentReference = new ImplementationB() // Some Other implementation } void behaviour1() { implmentReference.behave2(); } ............. }
ブリッジ :(構造パターン)
ブリッジパターンは、抽象化と実装を分離し、両方を独立して変更できるようにします。
次の場合にこのパターンを使用します:
- 抽象化と実装はコンパイル時に決定されていません
- 抽象化と実装は独立して変更する必要があります
- 抽象化の実装の変更は、呼び出し元のアプリケーションに影響を与えません
- クライアントは実装の詳細から隔離する必要があります。
戦略: (行動パターン)
戦略パターンを使用すると、実行時に複数のアルゴリズムを一連のアルゴリズムから切り替えることができます。
次の場合に戦略パターンを使用:
- アルゴリズムの複数のバージョンが必要です
- クラスの動作は実行時に動的に変更する必要があります
- 条件文を避ける
関連記事:
私は同じことを考えていましたが、最近、ブリッジを使用する必要があり、ブリッジは戦略を使用し、コンテキストを抽象化することで、後でクライアントを変更せずに変更を加えることができることに気付きました。抽象化なしでStrategyを使用する場合、設計はそれほど柔軟ではなく、後でクライアントを変更する必要があります。しかし、ブリッジ全体を使用すると、設計はさらに柔軟になります。ここで、StrategyからBridgeへの移行がどのように柔軟性を高めるかを確認できます。また、今では<!> quot; visa <!> quot;および<!> quot; master <!> quot;カードだけでなく、電話やチップでも利用できます。ブリッジを使用すると、そのサポートを簡単に追加できます。
デザインパターンタイプ
- 行動:パターンは、クラスまたはオブジェクトが相互作用して責任を分散する方法を特徴づけます
- 構造:パターンは、クラスまたはオブジェクトの構成を処理します。
- 創造的:パターンは、オブジェクトの作成プロセスを懸念します。
ブリッジ(構造)
リモコンを取ります。リモコンにはボタン1〜6があります。これは、上の図の具象クラスです。各ボタンは、リモコンがテレビまたはDVDに使用されているかどうかによって異なります。各ボタンの機能は、実装者インターフェースによって実装から抽象化されます。
これにより、各デバイスのリモコンの動作を変更できます。
戦略(行動)
戦略では、リモートシナリオを検討していました。 <!> quot; state <!> quot;コンテキストの状態参照を変更することで交換するリモート全体です。 <!> quot; concreteStateA <!> quot; (TVリモート)<!> quot; concreteStateB <!> quot; (DVDリモート)。
追加の読み物:
willcodejavaforfoodの回答に追加すると、実装は同じになります。ただし、戦略を使用して並べ替え戦略などの戦略を交換し、ブリッジを使用して2つのオブジェクト(データベースラッパーとネットワークアダプターなど)の実装をブリッジし、クライアントコードが同じAPIに対して動作するように使用できるようにします。そのため、実際にはネーミングにすべてが記載されています
-
戦略パターンは行動決定に使用され、ブリッジパターンは構造決定に使用されます。
-
Brigde パターンは実装の詳細から抽象要素を分離しますが、戦略パターンはアルゴリズムの互換性を高めることに関するものです。
Swiftの戦略パターン:
protocol PrintStrategy {
func print(_ string: String) -> String
}
class Printer {
let strategy: PrintStrategy
init(strategy: PrintStrategy) {
self.strategy = strategy
}
func print(_ string: String) -> String {
return self.strategy.print(string)
}
}
class UpperCaseStrategy: PrintStrategy {
internal func print(_ string: String) -> String {
return string.uppercased()
}
}
class LowerCaseStrategy: PrintStrategy {
internal func print(_ string: String) -> String {
return string.lowercased()
}
}
var lower = Printer(strategy: LowerCaseStrategy())
lower.print("I love Software Patterns")
var upper = Printer(strategy: UpperCaseStrategy())
upper.print("I love Software Patterns")
Swiftのブライドパターン:
protocol Appliance {
func run()
}
protocol Switch {
let appliance: Appliance {get set}
func turnOn()
}
class RemoteControl: Switch {
var appliance: Appliance
init(appliance: Appliance) {
self.appliance = appliance
}
internal func turnOn() {
appliance.run()
}
}
class TV: Appliance {
internal func run() {
print("TV is ON")
}
}
class Stereo: Appliance {
internal func run() {
print("Stereo is ON")
}
}
var tvRemote = RemoteControl.init(appliance: TV())
tvRemote.turnOn()
var stereoRemote = RemoteControl.init(appliance: Stereo())
stereoRemote.turnOn()
戦略パターンのウィキから
戦略のUMLクラス図 パターンは次の図と同じです ブリッジパターン。ただし、これら2つ デザインパターンは同じではありません 彼らの意図。戦略 パターンは行動を意味し、 ブリッジパターンは構造用です。
コンテキストと 戦略は 抽象化と ブリッジでの実装 パターン。
パターン比較について既に述べたことに加えて(意図の違い、...):Bridgeパターンも、抽象化階層側を変更できるように意図的に構造化されています。 C#のような言語では、これは、既存のコンシューマーに問題を引き起こさない意図されたバリエーションを許可する方法として、仮想メソッドを含む抽象化ベースがあることを意味します。それ以外は、2つのパターンがほとんどの部分で同一に見える場合があります。
戦略パターンは、実行時にアルゴリズムまたは戦略をプラグインする場合に使用されます。パターンのカテゴリは、オブジェクトの動作を扱うことも意味します。一方、ブリッジは構造パターンであり、オブジェクトの構造階層を処理します。それらの間に洗練された抽象化を導入することにより、抽象化を実装から分離します。洗練された抽象化は、プラグインされたランタイム戦略と混同される可能性があります(In Strategyパターン)。ブリッジパターンは、n個のクラスの作成を回避するメカニズムを提供することにより、構造的な側面を処理します。
戦略パターンの場合、実装のみが異なります。
仮に、クラスAが複数の実装が利用可能なクラスBを使用しているとします。したがって、その場合、Bは実行時に提供される実際の実装を使用して抽象的になります。これは戦略パターンです
A自体が抽象の場合。 AとBの両方が異なる場合があります。ブリッジパターンを使用します。
使用されているコンテキストでは、両者の間にわずかな違いがあると思います。
ブリッジパターンを使用して、両方がより大きな概念に属する直交概念を分離します。通常、複数の抽象化が含まれます。
IMO、戦略パターンはよりシンプルまたはよりフラットです。確かにOCPに役立ちますが、必ずしもブリッジパターンのような別のより大きなコンセプトの一部である必要はありません。