Chain of Responsibility パターン

Chain-of-responsibility パターン, CoR パターンは、オブジェクト指向設計におけるデザインパターンの一つであり、一つのコマンドオブジェクトと一連の処理オブジェクト  から構成される。各処理オブジェクトは、処理できるコマンドオブジェクトの種類と、自身が処理できないコマンドオブジェクトをチェーン内の次の処理オブジェクトに渡す方法を記述する情報を保持する。また、新たな処理オブジェクトをチェーンの最後に追加する機構を備える。

標準的な chain-of-responsibility のモデルの派生ハンドラーがディスパッチャとして動作し、コマンドを様々な方向に送出できるようにすることで、いわば //tree of responsibility// を形成しているものもある。

また、これを再帰的に行うケースもあり、処理オブジェクトが上位の処理オブジェクトを、問題の一部を解決するコマンドとともに呼び出すこともある。こうした場合再帰はコマンドが処理されるか、全てのツリーを巡回するまで継続される。XMLのインタプリタなどがこの例に当てはまるだろう。

このパターンはプログラミングにおいてよく用いられる、疎結合性を促進させる方法である。

1. 例
----

1.1. Java
---------

以下の Java コードは、ロギングクラスの例を用いてこのパターンを示したものである。各ロギングハンドラーはログレベルで何らかのアクションを起こすべきかどうかを判断し、次のロギングハンドラーにメッセージを渡す。

出力：

Writing to debug output: Entering function y. Writing to debug output: Step1 completed. Sending via e-mail: Step1 completed. Writing to debug output: An error has occurred. Sending via e-mail: An error has occurred. Writing to stderr: An error has occurred.

この例はロギングクラスをこの方法で書くことを推奨するものではなく、また、CoR の「純粋な」実装では、ロガーがメッセージを処理した後に、その責任を後段に渡すことはない。この例では処理されるかどうかに関係なく、メッセージがチェーンの先に渡される。

import java.util.*;

abstract class Logger { public static final int ERROR = 3; public static final int NOTICE = 5; public static final int DEBUG = 7; private final int mask; protected Logger { this.mask = mask; }

// The next element in the chain of responsibility protected Logger next; public Logger setNext { next = l; return this; }

public void message { if  { writeMessage; if  { next.message; } } }

abstract protected void writeMessage;

}

class StdoutLogger extends Logger { public StdoutLogger { super; }

@Override protected void writeMessage { System.out.println; } }

class EmailLogger extends Logger { public EmailLogger { super; }

@Override protected void writeMessage { System.out.println; } }

class StderrLogger extends Logger { public StderrLogger { super; }

@Override protected void writeMessage { System.out.println; } }

public class ChainOfResponsibilityExample { public static void main { // Build the chain of responsibility final Logger l = new StdoutLogger.setNext.setNext));

// Handled by StdoutLogger l.message;

// Handled by StdoutLogger and EmailLogger l.message;

// Handled by all three loggers l.message; } }<WtXmlEndTag />

1.2. PHP
--------

<?php abstract class Logger { const ERR = 3; const NOTICE = 5; const DEBUG = 7;

protected $mask; protected $next; // The next element in the chain of responsibility

public function setNext { $this->next = $l; return $this; }

abstract public function message; }

class DebugLogger extends Logger { public function __construct { $this->mask = $mask; }

public function message { if  { echo "Writing to debug output: {$msg}\n"; }

if ) { $this->next->message; } } }

class EmailLogger extends Logger { public function __construct { $this->mask = $mask; }

public function message { if  { echo "Sending via email: {$msg}\n"; }

if ) { $this->next->message; } } }

class StderrLogger extends Logger { public function __construct { $this->mask = $mask; }

public function message { if  { echo "Writing to stderr: {$msg}\n"; }

if ) { $this->next->message; } } }

class ChainOfResponsibilityExample { public function __construct { // build the chain of responsibility $l = new DebugLogger; $e = new EmailLogger; $s = new StderrLogger;

$e->setNext; $l->setNext;

$l->message; // handled by DebugLogger $l->message; // handled by DebugLogger and EmailLogger $l->message; // handled by all three Loggers } }

new ChainOfResponsibilityExample; ?><WtXmlEndTag />

2. 関連項目
-------

Interception パターン
Interceptor パターン
Single responsibility 原則

3. 外部リンク
--------

Article "[1]" by Michael Xinsheng Huang
Article "[2]" by David Geary
Article "[3]" by Mark Grand
[4]
[5]
[6]
[7]