Chain of Responsibility パターン (複数のオブジェクトを鎖状につなぎ, その中の任意のオブジェクトがある要求を処理するままで, 順次その鎖に沿って要求を受流していく)

[Chain of Responsibility] = [責任の連鎖]

このパターンは, ある要求の受け取り対象となる複数のオブジェクトに鎖状の関係を構築し, 要求を処理することが可能なオブジェクトに渡るまで, 順次, 構築した鎖状の関係に沿って要求を受流していくパターン.

このパターンを適用すると, [この要求はこのオブジェクトが処理する] などという司令塔的な役割 (結びつき) を利用者側が意識しなくて良くなり, 利用者側は [連鎖関係にある任意のオブジェクトに要求を投げるだけ], 処理側は [流れてきた要求が自身で処理できる場合は処理し, できない場合は, その要求を次のオブジェクトに渡すだけ] という役割分担が明確となる. (利用者側は, 処理の詳細まで意識する必要はない)

注意:

連鎖構造が深いと, 実際どのオブジェクトが処理しているのかわからなくなったり (保守性が低下) 処理速度の低下を招くので, 注意が必要.

役割

  1. Handler (処理者):
要求を処理するインタフェースを定義する. 自身で処理できない要求の場合に受流する先 ([Handler] を実装したオブジェクト) を格納するフィールドを定義する.
  1. ConcreteHandler[A|B] (具体的処理者):
[Handler] のインタフェースを実装する. 実際に要求を処理する (自身で要求を処理するか, 次のオブジェクトに要求を渡すか) クラスである.
  1. Client (利用者):
[Chain of Responsibility] パターンを適用したクラスを利用し処理する.

クラス図

[Chain of Responsibility] パターンを適用したクラスを利用し処理する.

_images/designpattern-chain_of_responsibility013.gif

ソースコード

  1. Handler.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public abstract class Handler{
    protected String name;
    protected Handler next;

    public Handler(String name){
	this.name = name;
    }

    public Handler setNext(Handler handler){
	this.next = handler;
	return handler;
    }

    public abstract void request(int req); // 抽象メソッド
}

2-1. ConcreteHandlerA.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class ConcreteHandlerA extends Handler{
    private int rangeS;
    private int rangeE;

    public ConcreteHandlerA(String name, int rangeS, int rangeE){
	super(name); // 使わなければならない
	this.rangeS = rangeS;
	this.rangeE = rangeE;
    }

    public void request(int req){
	if(req >= rangeS && req <= rangeE){
	    System.out.println(name + ": 私が失敗してくれるわ!");
	}else if(next != null){
	    System.out.println(name + ": 私では無理じゃ!次の者に出会え");
	    next.request(req);
	}else{
	    System.out.println(name + ": 次の者がおりませぬ");
	}
    }
}

2-2. ConcreteHandlerB.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class ConcreteHandlerB extends Handler{
    public ConcreteHandlerB(String name){
	super(name); // 親クラスのコンストラクタを使わなければならない
    }

    public void request (int req){
	if(req % 2 == 0){
	    System.out.println(name + ": ようこそ! 偶数は私のテリトリー");
	}else if(next != null){
	    System.out.println(name + ": 無念! 偶数以外は ... 次の方お願いします");
	    next.request(req);
	}else{
	    System.out.println(name + ": 無念! 偶数以外は ... 次もいない");
	}
    }
}
  1. Client.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public abstract class Client{
    public static void main(String[] args){
	Handler hand1 = new ConcreteHandlerA("A", 1, 10);
	Handler hand2 = new ConcreteHandlerA("B", 11, 20);
	Handler hand3 = new ConcreteHandlerA("C", 21, 30);

	Handler hand11 = new ConcreteHandlerB("D");

	// 責任のチャーンを構築
	hand1.setNext(hand2).setNext(hand3).setNext(hand11);
	hand1.request(31);
    }
}

上記のプログラムの実行結果:

[wtopia ChainofResponsibility]$ java Client
A: 私では無理じゃ!次の者に出会え
B: 私では無理じゃ!次の者に出会え
C: 私では無理じゃ!次の者に出会え
D: 無念! 偶数以外は ... 次もいない