Chain of Responsibility のパターンを読んでいるだけで、 decorator の使用よりもその使用を好むシナリオを想像するのに苦労しています。
どう思いますか? CoRにはニッチな用途がありますか?
任意の時点でチェーンを解除できるという事実により、Chain of ResponsibilityパターンとDecoratorパターンが区別されます。デコレータは、他のデコレータとの対話なしで一度にすべてを実行するものと考えることができます。チェーン内のリンクは、それぞれが前のリンクに依存しているため、一度に1つずつ実行されると考えることができます。
リンクを構成するチェーンとしてプログラムを概念化できる場合、各リンクがリクエストを処理するかチェーンに渡すことができる場合、Chain of Responsibilityパターンを使用します
Win32 APIを使用していたときに、それが提供するフック機能を使用する必要がある場合がありました。 Windowsメッセージのフックは、Chain of Responsibilityパターンにほぼ従っています。 WM_MOUSEMOVEなどのメッセージをフックすると、コールバック関数が呼び出されます。コールバック関数をチェーンの最後のリンクと考えてください。チェーン内の各リンクは、WM_MOUSEMOVEメッセージを破棄するか、次のリンクにチェーンを渡すかを決定できます。
その例でDecoratorパターンが使用された場合、WM_MOUSEMOVEメッセージが通知されますが、他のフックも同様に処理できないようにすることはできません。
Chain of Commandパターンが使用されるもう1つの場所は、ゲームエンジンです。繰り返しますが、エンジン関数、イベントなどをフックできます。ゲームエンジンの場合、機能を単純に追加する必要はありません。機能を追加し、ゲームエンジンがデフォルトアクションを実行しないようにします。
これらのパターンの違いは、チェーンがいつ(どのように)破壊されるか(チェーンを想定)または追加の動作が実行されるタイミングとは関係ありません。それらは、どちらもより柔軟なソリューションを提供するために継承を支持して構成を使用するという点で関連しています。
主な違いは、デコレータが追加することです 新着 実際に元のインターフェースを広げる動作。 「サブクラス」が参照によってのみ結合されることを除いて、通常の拡張機能がメソッドを追加する方法に似ています。つまり、「スーパークラス」を使用できます。
CORパターンは、継承を使用して既存のメソッドをオーバーライドするのと同様に、既存の動作を変更できます。 super.xxx()を呼び出して「チェーン」を続行するか、自分でメッセージを処理することを選択できます。
そのため、違いはわずかですが、デコレーターの例が役立ちます。
interface Animal
{
Poo eat(Food food);
}
class WalkingAnimal implements Animal
{
Animal wrapped;
WalkingAnimal(Animal wrapped)
{
this.wrapped = wrapped;
}
Position walk(Human walker)
{
};
Poo eat(Food food)
{
return wrapped.eat(food);
}
}
class BarkingAnimal implements Animal
{
Animal wrapped;
BarkingAnimal(Animal wrapped)
{
this.wrapped = wrapped;
}
Noise bark()
{
};
Poo eat(Food food)
{
bark();
return wrapped.eat();
}
}
歩く、barえる動物を作成できること、または実際に任意の動物にbarえる機能を追加できることがわかります。この追加の動作を直接使用するには、BarkingAnimalデコレータへの参照を保持する必要があります。
BarkingAnimalはすべて、食べる前に一度鳴きますが、これは既存の機能を変更したため、CORに似ています。しかし、その意図はCORと同じではありません。つまり、食物を食べる多くの動物の1つを見つけることです。ここでの意図は、動作を変更することです。
動物を散歩させる人間を見つけるためにCORが適用されることを想像できます。これは、上記のchained
のようなリンクリストとして、または明示的なリストとして...または何でも実装できます。
これが合理的に明確であることを願っています!
ジョン
チェーン
複数のオブジェクトにリクエストを処理する機会を与えることにより、リクエストの送信者を受信者に結合することを避けます。受信オブジェクトをチェーンし、オブジェクトが処理するまでチェーンに沿ってリクエストを渡します。
対
デコレーター
オブジェクトに追加の責任を動的に付加します。デコレータは、機能を拡張するためのサブクラス化の柔軟な代替手段を提供します。
私は、物事が起こる順序について言っていると思います。それらをチェーンすると、チェーンに沿って呼び出されます。デコレータを使用すると、この順序が保証されるわけではなく、追加の責任のみを付加できます。
Chain of ResponsibilityはDecoratorの特定の形式です。
デコレータは、オブジェクトに機能を追加するときに使用されます。
CORは、多くのアクターの1つがオブジェクトに対してアクションを実行する場合に使用されます。
A 特定デコレータは、タイプに基づいてアクションを実行するために呼び出されます。一方、CORは、アクタの1人がアクションの完了を決定するまで、定義されたチェーンに沿ってオブジェクトを渡します。
CORは、複数のレベルの異なるハンドラーへのエスカレーションがある場合に使用される場合があります。たとえば、会社に対する顧客の価値がコールが特定のレベルのサポートに行くかどうかを決定するコールセンターです。
まあ、私は2つの状況を考えることができます:
これ以上考えることはできません、このトピックでもっと聞きたいです。
Decorator
デコレータ パターンを使用すると、個々のオブジェクトに動作を動的に追加できます。
機能を拡張するためのsub classingの柔軟な代替手段を提供します。継承を使用していても、Lowest Common Denominator(LCD)インターフェイスから継承します。
デコレータのUML図
結果:
便利なリンク:
Decorator_pattern ウィキペディアから
decorator sourcemakingから
責任の連鎖:
責任の連鎖パターンは、コマンドオブジェクトのソースと一連の処理オブジェクトで構成される設計パターンです。各処理オブジェクトには、処理できるコマンドオブジェクトのタイプを定義するロジックが含まれています。残りはチェーン内の次の処理オブジェクトに渡されます
UMLダイアグラム
このパターンは次の場合により効果的です。
便利なリンク:
Chain-of-responsibility_pattern ウィキペディアから
chain-of-responsibility-pattern oodesignから
chain_of_responsibility sourcemakingから
現実世界の例:企業では、指定された役割には購入リクエストの処理に特定の制限があります。指定された役割を持つ人が購入請求書を承認するのに十分な権限を持っていない場合、彼はコマンド/リクエストを後継者に転送します。このチェーンは、コマンドが処理されるまで続きます。
構造的な観点から、この2つのパターンは非常に似ていることに同意します。私の考えは、最終的な動作についてです。
リクエストを処理するCoR要素の古典的な解釈では、チェーンが壊れます。
デコレータの要素がチェーンを壊した場合、動作の基本部分が失われるため、デコレータのwrong実装になります。また、デコレータの考え方は、基本動作に手を加えない場合に新しい動作を透過的に追加することです。
これら2つのパターンを適用する状況は異なると思います。ところで、デコレータパターンの場合、デコレータはラップしたコンポーネントを知っている必要があります。また、CoRの場合、異なるインターセプターは互いに何も知ることができませんでした。
Gang of Fourの定義を読んだ後、本当の違いがあるとは確信していません。 (便宜上含まれています)
ウィキペディアはそれらを少し誇張していますが、その一部はsome意的です。
最初の2つの属性は、実際にはパターンを区別しません。 2番目の2つは行いますが、デコレーターとCoRの通常の実装方法ではこれらの属性は強制されません。デザイナーは、データを処理した後にチェーンを中断するデコレーターまたはチェーンを継続するCoRLinkを誰も作成しないことを望んでいます。
これらの属性を実際に実装するには、次のようなものが必要です。
施行されたデコレータ:
abstract class Decorated {
public Decorated delegate;
public final Object doIt(Object args) {
Object returnVal = behavior(arg);
if(delegate != null) returnVal = delegate.doit(returnVal);
return returnVal;
}
protected abstract Object behavior(Object args); //base or subclass behavior
}
責任の強制チェーン:
abstract class Link {
public Link delegate;
public final Object processIt(Obect args) {
Object returnVal = args;
if(isMyResponsibility) returnVal = processingBehavior(returnVal);
else returnVal = delegate.processIt(returnVal);
return returnVal;
}
protected abstract Boolean isMyResponsibility(Object args);
protected abstract Object processingBehavior(Object args);
}
(あるいは、他の誰かがあなたのデザインを台無しにした場合の責任を自分自身に放棄することだけが必要な場合は、javadocに行を追加することもできますが、なぜそれを偶然に任せますか?)