導入
オブジェクト指向のプログラミング言語の機能の中でも目玉と呼べるものが
展開
必要な機能を持っているクラスを利用する仕組みが継承と委譲
継承や委譲を使う基本的なストーリーは次の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
に納めます。