高度な継承
〈高度な継承〉
まず前提として
親クラス…曖昧なクラス
子クラス…具体的なクラス
これまでの継承
目の前のプログラム開発に必要なクラスを作る開発者の立場で考える
(既存クラスを継承して子クラスを作る人)
開発チームの中で作るクラスの中から共通点がたくさんあるクラスを1つ作っておけば、それを他の人が継承して使ってくれると効率的
これから学ぶ継承
未来に備えて別の開発者が将来利用するであろうクラス(親クラス)を想定して準備しておく開発者
※ これまでの継承とこれからの高度な継承は作るときの立場が違うことを頭に入れておく
高度な継承を使う人の役割
…他の開発者が効率よく安心して利用できる継承の材料を事前に作っておくこと
(他の開発者や未来の開発者に少しでも楽をして効率よく作ってもらいたいという思いやりが大事)
↓
ただこのことを突き詰めると「2つの不都合、3つの心配事」が生じる
ex. public class Character{
private String name;
private int hp;
public void run( ){
System.out.println(this.name+"は、逃げ出した");
}
public void attack(Matango m){
System.out.println(this.name+"の攻撃");
System.out.println(" ? ポイントのダメージを与えた");
←?のところは継承されるまでどのキャラによって何ポイントダメージが与えられるのか分からない
m.hp-=??;
(ここもこの時点では具体的な値は決められない)
}
}
〈不都合A〉
継承材料となるクラスを作る時点では中身をまだ確定できない「詳細未定メソッド」がある
そもそもオブジェクト指向とは
「現実世界を正確に写し取る」ことが目的
↓
バグ=現実世界とJavaコード内の仮想世界に矛盾を生じる余地があるから生じる
ただ上記のコードのCharacterクラスで考えると(現実世界を自分の頭の中で考えてみると)
Characterの前提….「キャラクターであれば少なくとも攻撃くらいは出来るはず」
↓
attack( )の中身が詳細に書けないからといって、attack( )メソッド自体をなくして
「攻撃できないキャラが作れてしまう」というのはなし!
Characterクラスは必ずattack( )を持っているべき!
詳細未定のメソッドにしておくことで起こりそうな心配事3つ
1. 渡された側でのオーバーライド(上書き)のし忘れ
2. 何も書いてないと「上書きした方が良いのか」「本当に何もしない」のか区別がつかない
3. 継承用に作ったクラスも開発者が間違えて値が未定のままにも関わらず、newしようとすることもすることもある
↓
〈そもそもこのようなことが起こる原因〉
クラスには2つの利用の仕方があるから
① newによる利用
インスタンスを生み出すためにそのクラスを利用する方法
② extendsによる利用
別のクラスを開発する際、ゼロから作ると効率が悪いので、
そのクラスを継承元として利用する方法
ex. Characterクラス (extends)→ Heroクラス (new)→Heroインスタンス
〈解決策〉
心配事2に関して
何も書いてないメソッドだと「現時点で中身を確定できないメソッド」なのか「何もしないメソッド」なのか区別がつかない
↓
「詳細未定メソッド」だと分かるように専用の構文を記述すればOK
〈専用構文 アクセス修飾子〉
public abstract 戻り値 メソッド名(引数リスト);
※abstract→「抽象的、あいまい」という意味
ex. Characterクラスのattack( )メソッド
public class Character{
public abstract void atttack(Matango m);
↓
abstractと書くことで中身がまだ詳細でないことを表せる
また、メソッドの中身は未定なので記載しない { }でくくるのではなく、; にする
これで心配事2は解決!
(abstract)
心配事3に関して
継承用に作ったクラスを誤ってインスタンス化される可能性がある
↓
class宣言にabstractと記述することで、継承用であることを表す
ex. public abstract class Character{
private String name;
public abstract void attack(Matango m);
〈abstract ルール〉
抽象メソッドを含むクラスは必ずabstractつきクラスにしなければならない
→でないと、コンパイルエラー
抽象クラスでは、newによるインスタンス化が禁止される
心配事3は解決!
抽象クラス(abstract クラス名)として宣言すれば、間違ってnewされることはない
心配事①に関して
未来の開発者がnewする際に詳細未定メソッドをオーバーライド(上書き)し忘れる可能性がある
もしabstract付き詳細未定メソッドを未定のままインスタンス化しようとしたらどうなるか→コンパイルエラーになるのでインスタンス化出来ない
(Javaルール 未完成状態のものは必ずabstractをつけなければならない)
このエラーを解決してインスタンス化をするためには
方法① クラスにabstractをつけて抽象クラスにする ⇨これだとnewしてインスタンス化出来ない(本来の目的newしてインスタンス化が達成できない) ×
方法② そのメソッドの「未完成部分」を全てなくす ⇨これだとインスタンス化が出来る(本来の目的達成) ◯
このように消去法で考えると、
抽象メソッド(abstract)として宣言すれば、それを使う開発者がインスタンス化をしようとする際には
オーバーライド(上書き)をするしかない
心配事1は解決!
☆ ちなみに、メソッドの中身をオーバーライド(上書き)によって確定させることを「実装する」と表現する