http://wonderfulsky.web.fc2.com/oop.html
● メッセージバッシングの多用はプログラムの動作が追いにくい原因となる。関数でできるものは関数で実現するのがよいのではないか?
● デザインパターン本では派生クラスを多用しているサンプルプログラムが多いが、実際の開発でこのようなケースが有効につかえるのか?
業務アプリしか作ったことのない人の意見だなー。
今時のソーシャルゲームなら、幾らでもある話ですよ。
- 普通はプレイヤーキャラが、モンスターを倒す。
- しかし、プレイヤー同士が戦うこともある。
$player->attack($enemy)
と記述できた方が遥にメンテナンスしやすい筈です。
何故って、このまま右辺と左辺を入れ替えれば、先攻後攻が入れ替わるわけですよ。「static関数の引数の、2番めと3番めが入れ替わってる」より遥に直感的だと思うのですが。
- $player->attack($enemy);
- $enemy->attack($player);
- interface BattlePerson { function attack( BattlePerson & $target ); 他にも色々 }
- class PlayerPerson implements BattlePerson { 省略 }
- class MonsterPerson implements BattlePerson { 省略 }
チーム戦だったらどうします? 下手すると、3重ループぐらいに成りかねない。要するに、オブジェクト自身がどうこう、って言うんじゃなくて、呼出側が複雑化するわけです。
そうそう、ゲームは、攻撃力計算にも、バイアスやら倍率やら色々掛かるんですよ。防御力に同じく。おまけになんかアイテム持っていたら、必殺技が発動して、全体攻撃。敵全体にダメージ、とかやらなきゃならない。逆に、もちろんオブジェクト自体も複雑化するということです。
staticなんかとても呼んでられないですよ。
これをstaticで書ききるのは、それなりの技術と記憶力がないと無理でしょう。ただしそれをstatic宣言群の記憶で使い切るのは非常に勿体ない。
オブジェクト指向は「忘れる」ためにあるのですから。
前出の例で言うと、BattlePersonをimplementsすると言うことは、「攻撃相手に指定できる」ということでもあります。処理方法は、PlayerPersonを実装する時に頑張ればいいわけです。メソッドの向こうは、一旦忘れるべき。それが「カプセル化」の本来の意図でしょう。privateだのprotectedだのgetter/setterだのは、ガイドライン或いはコーディングルールの一つでしかない。
故に「プログラムが追いにくくなる」は全くの言いがかりです。或いは、逆ギレです。
- そういう脳の使い方に慣れてないだけ。もしくは、
- そのプログラムが「オブジェクト希望プログラミング」で書いてあるか。
- メソッド名のネーミングセンスが最悪か
え、「派生クラスの話は何処?」かって?それも説明しなくちゃ駄目?
例えば、attack()の中身の話をしていません。相手がモンスターだったりプレイヤーだったりで幾つか都合が有りますが、
- 攻撃力を求める
- 防御力を求める
- ダメージ計算をする
という辺りは変わりません。
public function attack( BattlePerson & $target ){そんな訳で、前にはinterfaceってことにしましたが、この関数は基底クラス預かりにしたほうが良さそうです。攻撃力、防御力は、プレイヤー、モンスターで別系統の処理が必要なので、派生クラスの責任にするしかありません。
$offence = $this->attackValue();
$defence = $target->defenceValue();
$damage = $offence - $defence;
$target->damage($damage);
}
abstract function attackValue();
abstract function detenceValue();
abstract function damage($damage);
後は実装の内容ですが、派生クラス間で、共有したい処理が幾つか出てくる筈なので、それを基底クラスに押し込むか、mix-inを使うか。もちろんPHPではmix-inは無理(ってことになってる)ので、入れ子クラスにするしかなかったりします。入れ子クラスの処理が追いにくいのは確か。Java族の悪しき伝統です。