デザインパターンを覚えたい (Composite)
Compositeパターン
共通メソッドによる再帰処理を行うパターン。
例えばファイルシステムの検索とかを実装する際に、FileクラスとDirectoryクラスを同一の親クラスを継承して作成することによって、クラスを同一視して扱うみたいな感じ。
Compositeパターンの特徴は。。。なんだろ、再帰が綺麗に作れること?
実装。ちょっとJavaの勉強したいので、前回に引き続きJavaでやります。
例としてゲームAIでよく出てくるミニマックス探索をやる。
http://dl.dropbox.com/u/7810000/code/design_pattern/composite.zip
実行結果は以下のとおり。
$ java -classpath classes Main
[RT] : 1
[RT] -> [c4] : 1
[RT] -> [c4] -> [c5] : 1
[RT] -> [c4] -> [e3] : 3
[RT] -> [e6] : -2
[RT] -> [e6] -> [f5] : -2
[RT] -> [e6] -> [f4] : 1
オセロの手の表記方法を意識してます。スコアはテキトー。
実装ではBranchとLeafとゲーム木の要素を2つに分けたけど、普通はNode一個で扱うんだろうね、たぶん。
ポイントはBranchの再帰処理のところ?実装がとっても汚い。
protected void printTree(Deque<String> selectList, Side curSide) { // XXX: 本当は表示とスコア計算を同時にやるべき int senteScore = (curSide == Side.SENTE ? getScore(curSide) : -getScore(curSide)); StringBuffer prefix = new StringBuffer(); for (String select : selectList) { prefix.append("[" + select + "] -> "); } System.out.println(prefix.toString() + "[" + getSelect() + "] : " + senteScore); // 再帰的にサブツリーを表示 Side nextSide = (curSide == Side.SENTE ? Side.GOTE : Side.SENTE); selectList.add(select); for (Node node : childNodes) { node.printTree(selectList, nextSide); } selectList.removeLast(); }
子ノードを呼ぶところで親元であるNodeクラスのprintTreeを呼んでいて、これは実体がLeafクラスだろうがBranchクラスだろうが呼びだす側としては同じに見ている。
そういえば、今回Dequeのadd/removeLastを使って実装してるけど、初めstackっぽくpush/popでやったら順序が変になったんだよね。なんでだろ、そういう仕様なのかな。