導入
オブジェクト指向のプログラミング言語の機能の中でも目玉と呼べるものが
展開
必要な機能を持っているクラスを利用する仕組みが継承と委譲
継承や委譲を使う基本的なストーリーは次の2通りが考えられます。
あるクラスAを作成した後に、
そのクラスAの機能と同じ機能を持ち、 さらに別の機能を持つクラスBを作成したくなったとします。このような場合に継承や委譲を用います。 あるいは、
あるクラスAとBが同じ機能を持つ良く似たコードを持っているとします。この良く似た部分のコードを切り出してクラスCにまとめるリファクタリングを行います。そしてクラスCを継承、 あるいは委譲するクラスA'とB'を作成します。
どちらも複数のクラスの間に、
単純に継承したクラスと、著作者名情報を取得するメソッドを追加したクラスをつくる
これから紹介するサンプルコードは、ConfigInfoクラスとします。そしてこれを継承したAppInfoLoader8クラスを作成します。さらに新しいクラスAppInfoLoader9には著作者情報を持たせ、TestAppInfoLoader6.とします。
以下のファイルはTestAppInfoLoader6フォルダに納めてください。CONFIG.とSETTING.はさらにその中のdataフォルダに納めてください。
「インターフェイスの実装」AppInfoLoader8クラスはコンストラクタとgetClassNameメソッドしか持ちません。それにもかかわらず、ConfigInfoクラスのメソッドを呼び出して使うことができます。目的の仕事をするメソッドをスーパークラスが持っていれば、
さらに追加の機能が欲しくなった場合、AppInfoLoader9では、ConfigInfoを継承した後に著作者名を取得するための新しいメソッドgetAuthorNameを追加しています。
プロトタイピング中など、ConfigInfoクラスへ吸収し、ConfigInfoクラスを継承するクラスを再構成するのです。
緻密な設計を必要とするクリティカルなシステムのコードではこんな行き当たりばったりな方法論は通用しませんが、
継承した後、今あるメソッドをオーバーライドする
クラスConfigInfoとクラスAppInfoLoader8やAppInfoLoader9を比較すると、getClassNameが定義されています。
ConfigInfoのgetClassNameメソッド private final String CLASS_NAME = "ConfigInfo";
public String getClassName(){
return CLASS_NAME;
}AppInfoLoader8のgetClassNameメソッド public static final String CLASS_NAME = "AppInfoLoader8";
// 中略
public String getClassName(){
return CLASS_NAME;
}このように、ConfigInfoを単体で使用する際には、getClassNameメソッドでクラス名を取得すると、ConfigInfoで定義されている定数CLASS_の値ConfigInfoが取得されます。
クラスAppInfoLoader8を使用する際には、getClassNameメソッドでクラス名を取得すると、AppInfoLoader8で定義されている定数CLASS_の値AppInfoLoader8が取得されます。 2つのクラスを使うコードの側から見ると、AppInfoLoader8のインスタンスのスーパークラスのクラス名が必要ならば、AppInfoLoader8内でsuper.と呼べば、
継承した後、今あるメソッドをオーバーロードする。すなわち引数が異なるメソッドを作成する
クラスConfigInfoにはloadConfigInfo()メソッドがあります。これは設定ファイル名を引数として受け取るように宣言されていますから、loadConfigInfoメソッドを定義します。次のsketch TestAppInfoLoader7を見てください。
以下のファイルはTestAppInfoLoader7フォルダに納めてください。CONFIG.はさらにその中のdataフォルダに納めてください。
次のコードのように、
AppInfoLoader10でオーバーロードしたloadConfigInfoメソッド。 public boolean loadConfigInfo(){
return super.loadConfigInfo(CONFIG_FILENAME);
}そして、
loadConfigInfoメソッド。 a.loadConfigInfo();こうなると、AppInfoLoader10への参照をクラスConfigInfoに代入して、AppInfoLoadr10でオーバーロードしたメソッドを呼んでも使用できません。このためクラスTestAppInfoLoader内のtestAppInfoLoaderメソッドの引数を変更しなければなりませんでした。継承を利用していて、
継承を使わず委譲で実現する
これまでで継承と、AppInfoLoader11は継承を使わずにこれまでと同等の機能を持たせています。
以下のファイルはTestAppInfoLoader8フォルダに納めてください。CONFIG.とSETTING.はさらにその中のdataフォルダに納めてください。
AppInfoLoader11の全体。public class AppInfoLoader11{
public static final String CLASS_NAME = "AppInfoLoader11";
public static final String AUTHOR = "Atsushi Hirata";
private static final String CONFIG_FILENAME = "CONFIG.TXT";
private ConfigInfo c = new ConfigInfo();
private String version = "0.0";
public AppInfoLoader11(){
c.loadConfigInfo(CONFIG_FILENAME);
version = c.getVersion();
}
public String getClassName(){
return CLASS_NAME;
}
public String getAuthorName(){
return AUTHOR;
}
public String getVersion(){
return version;
}
public boolean loadConfigInfo(){
boolean result = c.loadConfigInfo(CONFIG_FILENAME);
version = c.getVersion();
return result;
}
public boolean loadConfigInfo(String filename){
boolean result = c.loadConfigInfo(filename);
version = c.getVersion();
return result;
}
}クラスConfigInfoのコードはそのままです。ただし、AppInfoLoader11はそれを継承していません。クラス定義の先頭が
public class AppInfoLoader11 extends ConfigInfoではなく、
public class AppInfoLoader11となっています。せっかくある継承の仕組みですが、AppInfoLoader11の内部にクラスConfigInfoのインスタンスを持たせています。必要に応じてAppInfoLoader11がConfigInfoに仕事をたらい回しし、
欠点と言えば、
Java言語やProcessingではインターフェイスの仕組みがあり、
現実的な採用順
プロトタイピングに始まって完成に至るまでのプログラミングの過程において、
そのような場合には、
演習
演習1(難易度:easy)
高校生の成績を保持するクラスを作成しましょう。氏名、Baseをまず作成しましょう。その後に、Baseを継承したクラスScience、Humanitiesを作成してください。Scienceは物理、Humanitiesは古文、
演習2(難易度:easy)
演習1の問題において、Humanitiesは継承を用いず委譲を用いて書き直しましょう。
まとめ
- 継承、
オーバーライド、 オーバーロードという仕組みや、 委譲という工夫を学びました。
学習の確認
それぞれの項目で、
継承、
オーバーライド、 オーバーロードが理解できましたか? - 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
- 委譲の意味と役割が理解できましたか?
- 理解できた。気持ちよく納得した。
- 理解できた。しかし、
今ひとつスッキリしない。 - 理解できない。
参考文献
- 『Java言語プログラミングレッスン
(下)』(結城浩 著、 ソフトバンクくりエィティブ株式会社) - Java言語のオブジェクト指向的特徴を大変分かりやすく解説した入門書中の名著。上下巻ともにJava言語入門者は必携。
演習解答
- 以下のファイルをsketchフォルダ
TestResultsに納めます。 - 以下のファイルをsketchフォルダ
TestResults2に納めます。
