オブジェクト指向プログラミングa 第11回『クラスの継承 (後編)』〜  2.問題提起1(RPGキャラクターの例)


●ここでは, ロールプレイングゲーム(RPG)に登場するキャラクターとその戦闘システムを例に問題提起をする。

以前に例としてあげたRPGプログラムの例(まだ実行してみていない場合はまずこちらを実行してみること)で,
魔法使いMax君と騎士Jay君に戦ってもらったが,どうもMax君の方が強いようである。
そこで今度は,魔法使いMax君には RPGcharacter型オブジェクト (名前は "unknown") と戦ってもらおう。

以下のプログラムのうち,最後の RPGSystem.java のmainメソッドを少し変更する。

サンプルリスト (zipファイルなので,ダウンロードして展開し生成されたフォルダを,新規Javaプロジェクトを作成するときに読み込むこと。)
※Eclipseでフォルダごとプロジェクトとして読み込む方法は,Eclipseの解説ページの「5. 既存のフォルダから複数のソースファイルを読み込んでプロジェクトを作る」を参照のこと


これを実行してみると,なんと勝負がつかず,延々と戦い続けてしまうことが分かる。

原因は,RPGCharacter型オブジェクトの c3 が無敵だからである。これはバグと言っても良いだろう。こんなことは起こってはならないはずである。

なぜ,RPGCharacter型オブジェクトの c3 が無敵になってしまったか? それは,RPGCharacter型の defence( )メソッドと fight( )メソッドが何もしないように定義されているせいである。

つまり,Mage型オブジェクト c1 ("Max君")が

 c1.fight( c3 );

という具合に,c3に対して攻撃を行うと,

 c3.defence( c1からc3へ向けられたダメージ量 );

という処理を呼び出して,c3に防御をさせる。通常のdefence( )メソッドは

// Mageクラスの defence( )メソッド
public void defence(double damage) {
    damage = damage - (mp/5);     // 受けたダメージを軽減して
    if( damage < 0 ) damage = 0;  // 軽減しても残ったダメージ量を
    hp = hp - (int)damage;        // 自分のHPから引く
}
というように,受けたダメージを軽減した上で,自分のHPから軽減しきれなかったダメージ量を引くのだが,
RPGCharacter クラスの defence( ) メソッドは,以下の様に「何もしないように」定義されていて
//RPGCharacterクラスの defence( )メソッド
public void defence(double damage) {
 
}
いくらダメージを受けようが,自分のHPを減らす,という処理を行っていない。これでは,無敵になるはずである。
しかも,RPGCharacter の fight( )メソッドも,以下の様に「何もしないように」定義されていてるので
//RPGCharacterクラスの fight( )メソッド
public void fight( RPGCharacter c ) {

}

闘う相手に,ダメージを与えていない。

言ってみれば,RPGCharacter 型オブジェクトは無敵で有りながら,攻撃も行わないのである。これでは,闘いに決着がつかなくなるわけである。



●根本的な原因は,RPGCharacter 型は,RPGに登場するキャラクター全般を表すクラスで有り,具体的な振る舞い(各メソッドの具体的な処理)が定義できない
 という点にある。「何もしない」ことも,ソフトウェア上では不具合を起こすのである。かといって,適当な処理を定義することももちろん不具合の原因となってしまう。
 こうした事を防ぐには,このようなスーパークラスのオブジェクトは生成してはいけないのである。