デザインパターンを覚えたい (Prototype)
Prototypeパターン
Protorypeパターンの特徴はclassをnewするのではなく予め作成したインスタンスをコピーするところ。
メリットとしては、
- クラス名を明示的に指定しないため、プログラム間の依存性を小さくできる
- たくさんのクラスを扱うときに予めまとめておける
- インスタンスをコピーするので、newするのがめんどくさいクラスとかを使いやすい
というところですかね。コピー機にデータを突っ込んどいて、ほしい時にコピーしてもらうみたいなもので、使う側は中のデータのことを気にしなくていいってことでおk?
とりあえず実装してみる。今回はインスタンスのコピーが発生するので、それをどうやるかが問題。インスタンスのコピーは、
- JavaならCloneableを継承させてcloneメソッド
- C#ならICloneableのCloneメソッドを実装、中でMemberwiseCloneメソッドを呼ぶ
- C++だとcloneメソッド的なものはない?コピーコンストラクタとかで頑張る
とか。ある程度の高級言語ならcloneメソッド的なものはありそうな雰囲気。ただ、上に書いてるJavaとC#は浅いコピーなので、メンバに配列を持ってるとかの場合には不十分。深いコピーは自前実装するしかない?調べてるとシリアライズ化してコピるとかもあるとか。
Javaだと参考書とかぶるのでC#でやってみた。うーん、あんまりいい例が思い浮かばなかった。
http://dl.dropbox.com/u/7810000/code/design_pattern/prototype.zip
実行は次の通り。例の如くmonoが必要。
$ unzip prototype.zip
$ cd prototype
$ make
mcs -out:prototype_test Main.cs CalcManager.cs Calc.cs Add.cs Sub.cs Mul.cs Div.cs Fib.cs
mono prototype_test
register "足し算"
register "引き算"
register "掛け算"
register "割り算"
register "フォボナッチ10"
register "フォボナッチ20"
create clone of "足し算"
1 + 2 = 3
create clone of "引き算"
5 - 3 = 2
create clone of "掛け算"
3 * 4 = 12
create clone of "割り算"
8 / 2 = 4
create clone of "フォボナッチ10"
1 2 3 5 8 13 21 34 55 89
create clone of "フォボナッチ20"
1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946
コードのポイントは実際にインスタンスを作成して利用する部分。
// インスタンスの作成と利用 Calc addCalc = manager.create("足し算"); addCalc.calc(1, 2); Calc subCalc = manager.create("引き算"); subCalc.calc(5, 3); Calc mulCalc = manager.create("掛け算"); mulCalc.calc(3, 4); Calc divCalc = manager.create("割り算"); divCalc.calc(8, 2); Calc fib10Calc = manager.create("フォボナッチ10"); fib10Calc.calc(1, 2); Calc fib20Calc = manager.create("フォボナッチ20"); fib20Calc.calc(1, 2);
上のコード見ると、呼び出すときには実際に実装されているクラス名が一切出てこない。
なので、使う側ではクラス名とか意識する必要がないわけです(リフレクション使えば?とか言われちゃうとあれだけど)。
こうすると実装側を隠蔽できてコードの依存性が下がってとってもハッピー(という解釈でいいのかな?)。
あとはManagerへの登録も隠蔽すれば完璧ですな。