デザインパターンを覚えたい (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.xml

build:

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 done

BUILD 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");
    }
}

自分のコードがとっても汚いのが残念な感じですね。