Chain Of Responsibility
Chain Of Responsibilityは「責任の連鎖」というように訳すことができるでしょうか. 処理を数珠つなぎに連結して,順次,オブジェクトを渡り歩くような仕組みを備えています.
クラス構造
複数の処理を鎖のようにつなげて,それぞれ担当する処理をおこなう.それぞれが処理する具体的な内容をサブクラスで定義することにして,そのスーパークラスでは,抽象クラスとして,抽象メソッドとして定義しておく.
鎖のように連続するように,次の処理を誰が行うかという設定もあらかじめ行う.これによって,連続する処理に後から挿入したり,削除したりする作業が容易にできるようになる.その結果,判定者が順次処理を行う様子が,シーケンス図で確認することができる.
ソースコード
抽象クラス
抽象クラスとして,判定者クラスを作る.この判定者クラスでは,「判定する」ことを共通で定義するために,抽象メソッドとして定義しておく.この抽象メソッドをサブクラスで実装することで,個別の成績を判定する判定者のクラスを定義する.
abstract public class 判定者 { private 判定者 次の判定者 = null; abstract public void 判定する(受験生 ある受験生); public void 次の判定者を設定(判定者 次の判定者) { this.次の判定者 = 次の判定者; } public 判定者 次の判定者を取得() { return this.次の判定者; } }
サブクラス
判定者クラスを継承して,具体化したクラスの一つとして「試験判定者クラス」を以下のように定義する.「判定する」クラスを,試験成績を判定できるように実装する. さらに,次の判定者に回すために,設定されている「次の判定者」を取得して,次の判定者に判定してもらう.
/* * 試験の点数を判定する判定者を具体化 * 100点満点で,60点未満は不合格で,その時点で判定終了 * 60点以上では,試験合格として,次の判定に進む */ public class 試験判定者 extends 判定者 { @Override public void 判定する(受験生 ある受験生) { if(ある受験生.試験成績取得() < 60) { System.out.println("試験不合格"); } else { System.out.println("試験合格"); if(次の判定者を取得() != null) { 次の判定者を取得().判定する(ある受験生); } } } }
また,試験判定者に続いて,面接成績に基づいて判定する面接判定者を定義する.面接試験成績を基に判定するように,抽象メソッドを実装する. ここで,面接成績として,列挙型を用いている.enumという列挙型を定義する方法を用いて,面接成績を設定するための選択リストを作る.使うときには,この選択リストを型とする変数を設定し,その値は,選択リストから選ぶことになる.
enum 面接判定リスト { A,B,C,D }
/* * 面接成績を判定する * 面接成績は面接判定リストから選ばれている * D以上で合格とする */ public class 面接判定者 extends 判定者 { @Override public void 判定する(受験生 ある受験生) { if(ある受験生.面接成績取得() == 面接判定リスト.D) { System.out.println("面接試験不合格です"); } else { System.out.println("面接試験合格です"); if(次の判定者を取得() != null) { 次の判定者を取得().判定する(ある受験生); } } } }
/* *内申点から,合否を判定する. *内申点は10段階評価で7以上の点数で合格とする */ class 内申点判定者 extends 判定者 { @Override public void 判定する(受験生 ある受験生) { if(ある受験生.内申点取得() < 7) { System.out.println("内申点不合格です"); } else { System.out.println("内申点合格です"); if(次の判定者を取得() != null) { 次の判定者を取得().判定する(ある受験生); } } } }
受け渡しされるクラス
判定者を継承した,「成績判定者」や「面接判定者」などに判定してもらうためのデータを持っている「受験生クラス」を作る.この受験生クラスを,鎖のように連続している判定者がやり取りする.
public class 受験生 { private int 試験成績;//100点満点 private 面接判定リスト 面接成績;//A,B,C,D private int 内申点;//10段階評価 受験生(int 試験成績, 面接判定リスト 面接成績, int 内申点) { this.試験成績 = 試験成績; this.面接成績 = 面接成績; this.内申点 = 内申点; } public void 試験成績入力(int 試験成績) { this.試験成績 = 試験成績; } public int 試験成績取得() { return this.試験成績; } public void 面接成績入力(面接判定リスト 面接成績) { this.面接成績 = 面接成績; } public 面接判定リスト 面接成績取得() { return this.面接成績; } public void 内申点入力(int 内申点) { this.内申点 = 内申点; } public int 内申点取得() { return 内申点; } }
メインクラス
public class Main { public static void main(String[] args) { //試験判定員を作成 試験判定者 試験試験官 = new 試験判定者(); 面接判定者 面接試験官 = new 面接判定者(); 内申点判定者 内申点試験官 = new 内申点判定者(); //試験の順番を試験官の順番で指定する. 試験試験官.次の判定者を設定(面接試験官); 面接試験官.次の判定者を設定(内申点試験官); //受験生を作成する 成績は,試験の点数,面接の判定,内申点 受験生 受験生1 = new 受験生(80, 面接判定リスト.C, 8); 受験生 受験生2 = new 受験生(90, 面接判定リスト.D, 9); 受験生 受験生3 = new 受験生(50, 面接判定リスト.B, 7); //受験生毎に合格を判定する System.out.println("受験生1"); 試験試験官.判定する(受験生1); System.out.println("受験生2"); 試験試験官.判定する(受験生2); System.out.println("受験生3"); 試験試験官.判定する(受験生3); } }
実行結果
定義したクラスを用いて,メインクラスから実行した結果をに示す. 判定項目すべてが合格である受験生1では,全て合格の判定が出ている.注目してほしいのは,終了の表示について,「内申点判定終了」「面接判定終了」「試験判定終了」の順番で表示されている.判定を進めていく手順を終えた時点から,基に判定していた判定者にいったん戻っていることがわかる.
受験生1 試験合格 面接試験合格です 内申点合格です 内申点判定終了 面接判定終了 試験判定終了 受験生2 試験合格 面接試験不合格です 面接判定終了 試験判定終了 受験生3 試験不合格
演習
追加
試験判定の後に,実技試験を行うことに変更することになった. 実技試験を追加して,実技試験の結果によって,次の試験に進めるか進めないか判定する. なお,実技試験の結果は,「優」「良」「可」「不可」のパターンからなることとし,「不可」以外であれば,次の試験に進めることができるものとする.
新規作成
健康診断を受ける一連の流れをChain of Responsibilityのデザインパターンを用いて実装せよ.なお,血液検査と血圧測定,心電図を行い,それぞれで問題があれば,そこで緊急入院する処置をすることにする.