Chain of Responsibility

パターンの目的

p.237,line.3-5: 1つ以上のオブジェクトに要求を処理する機会を与えることにより、要求を送信するオブジェクトと受信するオブジェクトの結合を避ける。受信する複数のオブジェクトをチェーン状につなぎ、あるオブジェクトがその要求を処理するまで、そのチェーンに沿って要求を渡していく。

GoF パターンのクラス図

structure-08-05:chain

MixJuice 版 Chain of Responsibility (改善)

解決される GoF パターンの問題点

導入可能性の問題点
Chain of Responsibility パターンのクラスは要求を転送するためのインターフェースを持たなければならない。このため、そのインターフェースを持っていないクラスはパターンに参加できない。
拡張性の問題点

p.241,line.22-25: 3.要求を表現する。要求を表現するために別の選択が可能である。もっとも簡単な形式は、HandleHelpクラスの場合のように、要求をコーディングされたオペレーションの呼び出しとして実現する方法である。これは便利で簡単であるが、Handlerクラスが定義している要求しか転送できないことになる。

p.227, line.21-23, 3.Representing requests. Different operations are available for representing requests. In the simplest form, the request is a hard-coded operation invocation, as in the case of HandleHelp. This is convenient and safe, but you can forward only the fixed set of requests that the Handler class defines.

対策

Handler クラスに対するメソッド追加あるいはアブストラクトメソッド追加で解決できる。

結果

もともと Handlerクラスで定義していなかった要求も転送できるようになる。アブストラクトメソッド追加を行なった場合は、すべての ConcreteHandler に対してメソッド実装を追加する補完モジュールが必要になる。

また、もともと Chain of Responsibility パターンを使用していなくても、リスト状の構造があれば、Handler をスーパーインターフェースとして追加し、 HandleRequest メソッドを実装することによりパターンを導入できる。

構造

structure-08-09:chain

module original {
  define abstract class Handler {
    define abstract void handleRequestA();
  }

  define class ConcreteHandler1 extends Handler {
    void handleRequestA() {...}
  }

  define class ConcreteHandler2 extends Handler {
    void handleRequestA() {...}
  }
}

module extension extends original {
  class Handler {
    define abstract void handleRequestB();
  }

  class ConcreteHandler1 {
    void handleRequestB() {...}
  }

  class ConcreteHandler2 {
    void handleRequestB() {...}
  }
}

MixJuice によるデザインパターン改善カタログ


田中 哲 <akr@m17n.org>, 一杉 裕志 <y-ichisugi@aist.go.jp>