web-dev-qa-db-ja.com

デコレータよりも責任の連鎖を使用するのはなぜですか?

Chain of Responsibility のパターンを読んでいるだけで、 decorator の使用よりもその使用を好むシナリオを想像するのに苦労しています。

どう思いますか? CoRにはニッチな用途がありますか?

69
George Mauer

任意の時点でチェーンを解除できるという事実により、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つの場所は、ゲームエンジンです。繰り返しますが、エンジン関数、イベントなどをフックできます。ゲームエンジンの場合、機能を単純に追加する必要はありません。機能を追加し、ゲームエンジンがデフォルトアクションを実行しないようにします。

66
William Brendel

これらのパターンの違いは、チェーンがいつ(どのように)破壊されるか(チェーンを想定)または追加の動作が実行されるタイミングとは関係ありません。それらは、どちらもより柔軟なソリューションを提供するために継承を支持して構成を使用するという点で関連しています。

主な違いは、デコレータが追加することです 新着 実際に元のインターフェースを広げる動作。 「サブクラス」が参照によってのみ結合されることを除いて、通常の拡張機能がメソッドを追加する方法に似ています。つまり、「スーパークラス」を使用できます。

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のようなリンクリストとして、または明示的なリストとして...または何でも実装できます。

これが合理的に明確であることを願っています!

ジョン

17
John Patterson

チェーン

複数のオブジェクトにリクエストを処理する機会を与えることにより、リクエストの送信者を受信者に結合することを避けます。受信オブジェクトをチェーンし、オブジェクトが処理するまでチェーンに沿ってリクエストを渡します。

デコレーター

オブジェクトに追加の責任を動的に付加します。デコレータは、機能を拡張するためのサブクラス化の柔軟な代替手段を提供します。

私は、物事が起こる順序について言っていると思います。それらをチェーンすると、チェーンに沿って呼び出されます。デコレータを使用すると、この順序が保証されるわけではなく、追加の責任のみを付加できます。

13
Brian

Chain of ResponsibilityDecoratorの特定の形式です。

11
troelskn

デコレータは、オブジェクトに機能を追加するときに使用されます。

CORは、多くのアクターの1つがオブジェクトに対してアクションを実行する場合に使用されます。

A 特定デコレータは、タイプに基づいてアクションを実行するために呼び出されます。一方、CORは、アクタの1人がアクションの完了を決定するまで、定義されたチェーンに沿ってオブジェクトを渡します。

CORは、複数のレベルの異なるハンドラーへのエスカレーションがある場合に使用される場合があります。たとえば、会社に対する顧客の価値がコールが特定のレベルのサポートに行くかどうかを決定するコールセンターです。

8
Ragoczy

まあ、私は2つの状況を考えることができます:

  • コアオブジェクトがありません。つまり、すべてのレイヤー/フィルターを通過した後のリクエストの処理方法がわかりません。 (要求の終了位置を実際に気にしないインターセプターチェーンのような側面のようなもの)。
  • 要求に前処理または後処理を選択的に適用する必要があります。デコレータのような一般的な拡張形式ではありません。つまり、フィルターは特定のリクエストを処理する場合と処理しない場合がありますが、デコレーターを追加すると、常に何らかの機能でオブジェクトが強化されます。

これ以上考えることはできません、このトピックでもっと聞きたいです。

4
MahdeTo

Decorator

  1. デコレータ パターンを使用すると、個々のオブジェクトに動作を動的に追加できます。

  2. 機能を拡張するためのsub classingの柔軟な代替手段を提供します。継承を使用していても、Lowest Common Denominator(LCD)インターフェイスから継承します。

デコレータのUML図

UML diagram for Decorator

結果:

  1. 装飾を使用すると、追加された機能を動的に削除することもできます。
  2. デコレーションは、実行時にオブジェクトに機能を追加するため、システム機能のデバッグが難しくなります。

便利なリンク:

デコレータパターンを使用する場合

Decorator_pattern ウィキペディアから

decorator sourcemakingから

責任の連鎖:

責任の連鎖パターンは、コマンドオブジェクトのソースと一連の処理オブジェクトで構成される設計パターンです。各処理オブジェクトには、処理できるコマンドオブジェクトのタイプを定義するロジックが含まれています。残りはチェーン内の次の処理オブジェクトに渡されます

UMLダイアグラム

enter image description here

このパターンは次の場合により効果的です。

  1. 複数のオブジェクトがコマンドを処理できます
  2. ハンドラーは事前に知られていない
  3. ハンドラーは自動的に決定される必要があります
  4. 受信者を明示的に指定せずに、リクエストがオブジェクトのグループに宛てられていることが望まれます
  5. コマンドを処理できるオブジェクトのグループは、動的な方法で指定する必要があります

便利なリンク:

Chain-of-responsibility_pattern ウィキペディアから

chain-of-responsibility-pattern oodesignから

chain_of_responsibility sourcemakingから

現実世界の例:企業では、指定された役割には購入リクエストの処理に特定の制限があります。指定された役割を持つ人が購入請求書を承認するのに十分な権限を持っていない場合、彼はコマンド/リクエストを後継者に転送します。このチェーンは、コマンドが処理されるまで続きます。

2
Ravindra babu

構造的な観点から、この2つのパターンは非常に似ていることに同意します。私の考えは、最終的な動作についてです。

リクエストを処理するCoR要素の古典的な解釈では、チェーンが壊れます。

デコレータの要素がチェーンを壊した場合、動作の基本部分が失われるため、デコレータのwrong実装になります。また、デコレータの考え方は、基本動作に手を加えない場合に新しい動作を透過的に追加することです。

1
xenn_33
  1. キーワード「extends」-静的拡張。
  2. デコレータパターン-動的拡張。
  3. Chain of Responsibilityパターン-一連の処理オブジェクトでコマンドオブジェクトを処理するだけで、それらのオブジェクトはお互いを知りません。
1

これら2つのパターンを適用する状況は異なると思います。ところで、デコレータパターンの場合、デコレータはラップしたコンポーネントを知っている必要があります。また、CoRの場合、異なるインターセプターは互いに何も知ることができませんでした。

0
hewei1997

Gang of Fourの定義を読んだ後、本当の違いがあるとは確信していません。 (便宜上含まれています)

  • デコレータ:オブジェクトの動的なラッピングにより、既存の責任と動作を変更できます
  • 責任の連鎖:受信オブジェクトをリンクすることにより、複数のオブジェクトにリクエストを処理する機会を与えます

ウィキペディアはそれらを少し誇張していますが、その一部はsome意的です。

  • デコレータは通常、リンクリストとして実装されます。しかし、それはパターンの「一部」と見なされるには低すぎると思います。
  • Chain of Responsibilityリンクは、データが責任を負う場合にのみデータを処理します。しかし、責任の決定とデータ処理は両方とも行動の一部です。デコレータはこれを簡単に行うことができます。
  • デコレータでは、デリゲートを呼び出す必要があります。
  • 「純粋な」CoRリンクは、データを処理しない場合にのみデリゲートを呼び出す必要があります。

最初の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に行を追加することもできますが、なぜそれを偶然に任せますか?)

0
Kevin Sagan