ご意見くださって、ありがとうございます。
例にあげたRPGのモデル設計はhttp://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1178047006を参考にしました。
ですが自分で書くとしても、十中八九そのような設計にするでしょう。
モンスター.attack(勇者.attackPower)
勇者.attack(モンスター)
主語.動詞(目的語)
モデルに対する命令は、ふつう入力Controllerのイベントハンドラに書かれる。attackに関する命令はどちらの設計をとったとしても"攻撃が選択された"イベントハンドラに書かれるだろう。
モンスター.attack(勇者.attackPower)
だと、たとえばモンスターにダメージを与える要素として、他に「すばやさ」などを加えようとしたら、モンスターのattackメソッドを変更する必要が生じる。
また、FF5には"竜騎士のジャンプ"という攻撃方法があった。ジャンプを選択すると、竜騎士は空高く飛び、一定時間が経ったのちに落ちてきて、空中からモンスターを攻撃する、というもの。これを実装しようとすると、入力Controllerのイベントハンドラの直前の部分で別スレッドに投げるなり、タイマーを起こすなりして処理したくなる。
味方同士の”連携攻撃”を実装しようとするとやはり、入力Controllerのイベントハンドラを修正したくなるだろう。
つまり、悪い方の設計ではModel「勇者」への設計変更の都合で、Model「モンスター」や入力Controllerを修正する必要が出てきてしまう。
勇者.attack(モンスター)
では、どの設計変更の例でも、勇者側を変更するだけで良い。この設計には、クラス間の責任の分担がはっきりするという利点がある。
list.append(elem)でしょ。
リストは実質的にはオブジェクトというより、ただのデータ構造。
リストやディクショナリ(連想配列)は便利な道具だが、これを前面に押し出した設計は複雑さを招く場合がある。
たとえば、"複数のモンスターの集まり"や"ソートされたリスト"を、リストを継承して実装しようとすると、とたんにドツボにハマる。
Onスライムが仲間を呼んだ(){ スライムの集まり.append(スライム) スライムの個数ラベル.更新(スライムの集まり.length) if(スライムの集まり.length == 1 and スライムの集まり.get(0).name == "キングスライム"){ スライムの名前ラベル.更新("キングスライム") } }
スライムは8匹集まるとキングスライムになるので、最初の一行でスライムの集まりを変更して以降、スライムの個数を気にする必要があることに注意して欲しい。
上記のコードを洗練させるために、Model「スライムの集まり」で個数が変わった時にイベント"OnLengthChange"を発行するようにしても良いが、そのようにすると、lengthメソッドを安全に呼べるのはそのイベントハンドラのみ、ということになる。プログラマに注意を促すために、lengthメソッドのコメントにその旨を注意書きしておく必要がある。
"スライムの集まり"リストクラスは、プログラマが期待するだろうリストクラスの振る舞い《append後の個数はappend前+1》を破壊している。
"ソートされたリスト"は、appendメソッドをオーバーライドして、追加時に勝手に順番を並び替えてくれるようなものだが、これも《リストに要素を追加した時には、その要素は末尾に置かれる》というリストクラスの振る舞いを破壊する。スライムの例と同じように、イベントの発行とメソッドの注意書きが必要になる。プログラマはそれらのクラスを使うときに、より注意深くならなくてはいけない。
このように、クラスの振る舞いを壊してしまうようなクラス設計は、プログラマを地雷原におくりこむことになる。
とはいえ、リストのようなデータ構造を便利に使えるシーンもある。
はじめからおわりまで100行程度のスクリプトで、とくにイベントドリブンにするほどの複雑さがない場合。順序を追って読めるので、時間的な流れがわかりやすい。
一方、RPGの例で示したような設計は、オブジェクト指向をフルに使って、コードを責任に応じて役割分担しやすくなる利点がある。
前者は"トランザクションスクリプト"的設計と呼ばれ、後者は"ドメインモデル"設計と呼ばれる。
例えばスーファミのFFみたいな、古典的なRPGの戦闘シーンを作っていて、「勇者がモンスターを攻撃する」。 勇者.attack(モンスター); という設計だったとする。 これに「モンスターが毒...
MVC以前にオブジェクト指向がしっくりきてないでしょ。 「勇者がモンスターを攻撃する」。 勇者.attack(モンスター); という設計だったとする。 これが既にオブジェクト指向的じゃな...
ご意見くださって、ありがとうございます。 例にあげたRPGのモデル設計はhttp://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1178047006を参考にしました。 ですが自分で書くとしても、十中八九そ...
英語として読みにくいなら、メソッド名のほうを変えるよ。 モンスター.attackedBy(勇者.attackPower) 攻撃方法が増えるなら、攻撃方法を抽象化するでしょ。 攻撃方法型を作って モンスター....
一理あるご意見をいただきました。ありがとうございます。 英語として読みにくいなら、メソッド名のほうを変えるよ。 モンスター.attackedBy(勇者.attackPower) 誤解を招いてしまったよ...
わかりやすさについてとやかく言わないけどさ、攻撃するってことは、モンスターのHPだとかが減るんだよね? 勇者.attack(モンスター) って書いたとしてもさ、勇者.attackメソッドの中で、...
守備力だとか、耐性だとかは、モンスターの属性なので、影響はモンスター側で面倒見てもらいたいから、 攻撃でHPを減らすのは、モンスターのメソッド経由になると思う。 結局、 c...
モデルで発生するイベントが多く、複雑になるほど、ビューとの関連は密になる。 ここの所は、今回の例ではいまいち見えづらい気がする。今回の例で複雑になっているのはモデルだ...
元増田です。ありがとうございます。 モデルで発生するイベントが多く、複雑になるほど、ビューとの関連は密になる。 ここの所は、今回の例ではいまいち見えづらい気がする。 ...