んでは、Storekeeper(倉○番)の設計を始めてみようかな、と。
設計なんて言っても、そんな大それたモンじゃなく、どんなモノが出てくるとか、それぞれのモノがどう動くかとか、どういう風に関連しあってるかとか、全体的な流れなどなど、整理してみるわけですよ!(サンボマスター風に)
まずは、キー入力をどう受け取るか考えてみる。
それぞれのモノが、各々キー入力判定をしてみてもいいんだけど、こういうシステム依存的なコードは、なるべく一箇所に集中したいのココロ。なので、キー入力を受け取るクラスを作る事に。
■ Key
キー入力を input() メソッドで受け取るクラス。
倉○番では、方向キーしか使わないので input(direction) にするべか。
それぞれのオブジェクトにキー入力があった事を通知するのは、Observer パターンを使う事にする。
というわけで、Key は Observable(Subject) を継承して、input が呼ばれたら、接続してる Observer を、入力された方向を引数に update するってことで。
次に、倉○番の「舞台」が必要ですな。何しろ舞台が無いことには、主人公も倉庫の荷物も置けません。
■ Field
舞台となるクラス。1つの主人公と、複数の荷物を持っている。
複数の荷物は、リストか何かで管理するとして。
あと、大事なのが地形。ステージがどういう形なのかを、ここに持たせる。つまり、ここに移動できるかとか、ここには荷物があるか、などはこれに問い合わせればわかるって事で。
さらに、ゲームの終了を判定しなくちゃいけない。終了条件は、全ての荷物がゴールにある事なので、これじゃないと判定できない。荷物が移動したかどうかは、教えてもらわないとわからないので、Observer を継承して、Update してもらう事にする。
主人公の初期位置とか、ステージの形とか、荷物の数・位置は、ファイルに書いておいて、読み込むようにするべさ。
Model-View の Model にあたるクラスなので、Observable も継承して、View に通知できるようにしておく。
なんか、役目が多いな… しょうがないけど。
今度は、荷物クラスだけど、色々な種類の荷物を作れるようにする為に、荷物抽象クラスを作る事にする。荷物って英訳すると何だろ。Baggage …だと、手荷物って感じだし… Package だと、java.lang.Package とかぶっちゃうし… Box でいいや。箱〜。
■ Box(abstract class)
荷物(箱)を表す抽象クラス。
コンストラクタで、初期位置を設定。位置は、ゲッタだけ提供して、動かすには「押す」。「押す」のはどんな荷物でも出来るけど、実際に動くかどうかは押してみないとわからない、というわけで、「押す」は、実際に動いたかどうかを bool で返す。引数には押す方向かな。
あと、移動先に移動できるかどうか知る必要があるので、コンストラクタで Field を渡す事にしましょ。依存しちゃうけど、しょうがあるまい。
んで、移動した時に Field に伝える必要があるので、Observable を継承して、接続できるようにしておく。
具体的な箱としては、「押せない HeavyBox」「押すとその方向に1つ動くけど他の荷物があると押せない StepBox」「押すと壁や他の荷物にぶつかるまで動く箱 SlipBox」「押すとその方向に1つ動き他の荷物がある場合は飛び越えて2つ進む JumpBox」などが考えられる。どれも「押す」メソッドは共通。
…あれ? ちょっと待てよ。って事は、Field がファイルを読み込んで舞台を構築する時に、それぞれの荷物の種類に応じてインスタンスを作らないとだめだぞ。
…ここは、Javaお得意のリフレクションの出番ですか!(リフレクションを使えば、クラス名からインスタンスを生成したりできるみたい)
Class.forName("StepBox") で、StepBox のクラス型クラスをゲッツ! んで、getConstructor(Class[])で、コンストラクタをゲッツゲッツ! そして newInstance(Object[]) で、インスタンスを生成してゲッツゲッツゲッツ!
はぁ… はぁ…
すげーぞJava!これ便利すぎ!ぶっちゃけありえなーい!!
という事で、Box に追加。
■ 追加: Box
static な getBox(String classname, Field field, Point pos) メソッドを持つ。classname の Box を、field と pos を使ってコンストラクタを呼んでインスタンスを返すファクトリーメソッド。
つまり、Box の派生クラスは (Field, Point) のパラメータで呼べるコンストラクタを提供する。
次に、主人公。まー、主人公はほとんど考える所ないか。
■ Keeper
主人公(倉○番)を表すクラス。
コンストラクタで、初期位置を設定。荷物と同じく、位置はゲッタだけ提供して、動かすには Move(direction) で。Key に接続できるように、Observer を継承。Key から Update されたら、渡された方向へ Move する事にしませう。
Move する時に、移動先に Box があれば、Pushしてみる。true が返ってきた(動かせた)ら、移動する。
Box と同じく、移動先の問い合わせを Field にするので、コンストラクタで Field も渡す必要があるな。
このぐらいでしょうか。あとは、GUI部分だけど、この辺は後で考えるとして。
interface の使いどころが思いつかなかったのが心残り。実装の時に思いつくかも知れないですけども。
ってか、UMLで描くべきか…。ごめんなさい、UMLは勉強中で、描くのに時間がかかりすぎです。orz
何か良いアイデアがあればコメントください。
戯言