デザインパターンを覚えたい (Mediator)
Mediatorパターン
相談役は一人、なパターン。クラス間のやり取りをMediatorとなるクラスを介して行うことで、処理のパスを一箇所に集約する。
ポイントは
- クラス間の通信パスをスター型でまとめることでプログラムの見通しが良くなる
- Mediatorに相談するColleagueクラス群が再利用しやすい、一方でMediator役は再利用しにくい
とかかな。処理を集約する点がFacadeパターンと似てるけど、Facadeはメソッドをまとめて一方的に使うのに対して、Mediatorパターンは双方向でやり取りする点が異なるとか。
実装。Javaのマルチスレッドで遊んでみる。内容は1人のManager (Davit) と3人のWorker (Alice, Bob, Charlie) のタスク処理。
Workerはスレッドとして動作 (地味にスレッド処理ではまって時間かかった、よくないね)
http://dl.dropbox.com/u/7810000/code/design_pattern/mediator.zip
実行結果は以下のとおり。
# 結構時間がかかるので注意
$ ant test
Buildfile: /Users/xxx/tmp/mediator/build.xmlbuild:
test:
[java] Davit: assign task "create core module" to Alice
[java] Davit: assign task "create user interface" to Bob
[java] Davit: assign task "make API document" to Charlie
[java] Alice: do task "create core module"
[java] Bob: do task "create user interface"
[java] Charlie: do task "make API document"
[java] Charlie: done after 3 hours, report to manager
[java] Davit: assign task "buy lunch for all members" to Charlie
[java] Charlie: do task "buy lunch for all members"
[java] Bob: done after 4 hours, report to manager
[java] Davit: assign task "test modules" to Bob
[java] Bob: do task "test modules"
[java] Charlie: done after 1 hours, report to manager
[java] Davit: assign task "make powerpoint for sales" to Charlie
[java] Charlie: do task "make powerpoint for sales"
[java] Alice: done after 5 hours, report to manager
[java] Davit: assign task "cleanup the desk" to Alice
[java] Alice: do task "cleanup the desk"
[java] Alice: done after 1 hours, report to manager
[java] Alice: go home
[java] Charlie: done after 2 hours, report to manager
[java] Charlie: go home
[java] Bob: done after 6 hours, report to manager
[java] Bob: go home
[java] Davit: all task doneBUILD SUCCESSFUL
Total time: 10 seconds
ポイントはWorkerがManagerのメソッドを、ManagerがWorkerのメソッドを相互に呼び合っていることと、やり取りはManagerとWorker間のみでWorker同士では行われないこと。
public class Manager implements Mediator { /* 中略 */ public synchronized void reportTask(Task task) { Worker worker = assignMap.get(task.getName()); assignMap.remove(task.getName()); if (taskList.size() > 0) { Task newTask = taskList.removeFirst(); System.out.println(name + ": assign task \"" + newTask.getName() + "\" to " + worker.getWorkerName()); assignMap.put(newTask.getName(), worker); // Workerへタスクを割り当てる worker.assignTask(newTask); } else { worker.setEnd(); if (assignMap.size() < 0) { isEnd = true; } } } }
public class Worker extends Thread implements Colleague { /* 中略 */ public void run() { while (!isEnd) { if (hasTask) { System.out.println(name + ": do task \"" + task.getName() + "\""); try { Thread.sleep(task.getManHour() * 1000); } catch (Exception e) { System.out.println("ERROR: Woker sleep: exception occured : " + e); } hasTask = false; System.out.println(name + ": done after " + String.valueOf(task.getManHour()) + " hours, report to manager"); // Managerへタスクを報告する mediator.reportTask(task); } else { System.out.println(name + ": no task, take a break"); try { Thread.sleep(500); } catch (Exception e) { System.out.println("ERROR: Woker sleep: exception occured : " + e); } } } System.out.println(name + ": go home"); } }
自分のコードがとっても汚いのが残念な感じですね。