例えばスーファミのFFみたいな、古典的なRPGの戦闘シーンを作っていて、「勇者がモンスターを攻撃する」。
勇者.attack(モンスター);
という設計だったとする。
これに「モンスターが毒を受けて、自死する」という挙動を追加するケースを考える。
毒.attack(モンスター);
やや複雑な変更になりそうだが、勇者の攻撃とのタイミングの差で、
のようになるとしよう。
まず、インターフェイス"攻撃者"をつくって、「勇者」、「毒」をその実装とする。加えて...
斬撃後に死んでいた場合(*) 、納刀する
攻撃前に既に死んでいた場合、攻撃できないようにする
この設計変更によって、
が、
の4パターンに増えた(※ただし最後のパターンに関しては今回特に修正の必要はなかった)
攻撃者がひとつ増えるごとに、これらの分岐は倍、倍に増えていく怖れがある。
あらたに攻撃者を追加すると、既存の攻撃者を変更しなければならない。
この変更によって、全体の時間的な流れがよくわからなくなった。
等々の分岐が並ぶことになる。この分かりにくさは単にStateパターンを導入しただけでは本質的には改善しないだろう。
MVCにおけるモデル、は振る舞いを持ったデータだ。モデルが状態変化したとき、イベントが発生する。
しかしその状態変化が別のモデルの状態変化のタイミングに影響をうけるとき、モデルの設計はとても複雑になり、読みにくくなってしまう。
モデルで発生するイベントが多く、複雑になるほど、ビューとの関連は密になる。
このような複雑さをプログラマが支配するのは、とても大変だ。
みなさんも体験したことがないだろうか、GUIで「ホニャララしているときにホゲホゲするとバグる」みたいな挙動を。
すると、上部に表示される「更新時刻」の表示位置がおかしくなる。
RPGの設計は、たとえば下記のように記述できるDSLを導入すると、劇的に改善する。
タイミング:毒 ⇒ 死ぬ ⇒ 斬撃 の順なら、納刀する タイミング:毒 ⇒ 斬撃 ⇒ 死ぬ の順なら、変色した血が飛び散る
オブジェクト指向ではこれはStateパターンとStrategyパターンを組み合わせることで実現できる。
でも、このような設計にすると、勇者やモンスターのモデルオブジェクトの責任は極端に少なくなってしまう。
加えてオブジェクト間のやりとりの複雑さがDSLに押し込められるので、オブジェクトの主体性も殆ど無くなってしまい、
うん、ただのデータでいいや。
---------------------------
(*) 攻撃時に相手の状態を問い合わせるのが醜い。これを避けるには、モンスターが毒で死んだ時に勇者にイベントを通知して、勇者を”戦意喪失”状態に変化させる手がある。
MVC以前にオブジェクト指向がしっくりきてないでしょ。 「勇者がモンスターを攻撃する」。 勇者.attack(モンスター); という設計だったとする。 これが既にオブジェクト指向的じゃな...
ご意見くださって、ありがとうございます。 例にあげたRPGのモデル設計はhttp://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1178047006を参考にしました。 ですが自分で書くとしても、十中八九そ...
英語として読みにくいなら、メソッド名のほうを変えるよ。 モンスター.attackedBy(勇者.attackPower) 攻撃方法が増えるなら、攻撃方法を抽象化するでしょ。 攻撃方法型を作って モンスター....
一理あるご意見をいただきました。ありがとうございます。 英語として読みにくいなら、メソッド名のほうを変えるよ。 モンスター.attackedBy(勇者.attackPower) 誤解を招いてしまったよ...
わかりやすさについてとやかく言わないけどさ、攻撃するってことは、モンスターのHPだとかが減るんだよね? 勇者.attack(モンスター) って書いたとしてもさ、勇者.attackメソッドの中で、...
守備力だとか、耐性だとかは、モンスターの属性なので、影響はモンスター側で面倒見てもらいたいから、 攻撃でHPを減らすのは、モンスターのメソッド経由になると思う。 結局、 c...
モデルで発生するイベントが多く、複雑になるほど、ビューとの関連は密になる。 ここの所は、今回の例ではいまいち見えづらい気がする。今回の例で複雑になっているのはモデルだ...
元増田です。ありがとうございます。 モデルで発生するイベントが多く、複雑になるほど、ビューとの関連は密になる。 ここの所は、今回の例ではいまいち見えづらい気がする。 ...