抽象クラスは文字通り抽象的存在のクラスであり具体的な処理はこれを継承したクラスに記述させます。抽象クラスの存在意義は複数のクラスに対して共通性を持たせることであり、クラス設計においてとても重要な役割を担っています。
抽象クラスの特徴として、具象クラス(通常のクラス)との違いを挙げます。
抽象クラス及び抽象メソッドの書式は次の通りです。
abstract class クラス名 { abstract 戻り値 メソッド名(引数リスト) ; }
※抽象クラスには通常のメソッドも記述できます。また抽象メソッドは省略可能(抽象クラスの意味がないですが)です。
抽象クラスについては、実際の使用例を見たほうが理解しやすいと思いますので、例として、とある会社の社員クラスの設計を考えてみます。
社員クラスの条件は次の通りです。
このとき社員クラスを次のように考えたとすると・・・
これでは働くという処理に対して、営業部、開発部、総務部の区別をつける事が出来ません。これをどう解決するか?
次の2つが考えられます。
この2つの解決方法に対するメリットとデメリットとしては、次のようなことが挙げられます。
メリット | デメリット | |
1の解決方法 | 各クラスの仕様の変化やクラスの追加などに対して他のクラスへの影響を抑えることができる。 | 各クラス共通の処理も個別に記述しなければならない。また各クラスを個別に記述することで統一性(メソッドのシグニチャなど)が保たれる保障がない。ミスをしてもコンパイル段階では判別できない。 |
2の解決方法 | 各部署の社員クラスを社員クラス1つで呼び出せるので、各クラスを使用する側からみて取り扱いが楽になる。 | 1つの修正が全体に影響を及ぼす危険性が増える。 |
どちらを選択したらよいでしょうか・・・?
実はこのような時に抽象クラスを使用すると、その威力を発揮してくれます。
社員クラスを抽象クラス、そして「働く()」を抽象メソッドとして次の様な構成を考えます。
これにより上記2つの解決方法で、その両方のメリットを担保しつつ、それぞれのデメリットが解消されているのが解るでしょうか。
つまり次のようになります。
このように抽象クラスはクラスの構成を考える上でとても有効な手段となることが理解できると思います。
実際のソースを次に示しますので動作確認してください。
・サンプルソース(Sample0901.java)
abstract class Employee0901 { protected String name="社員"; abstract void work(); // 抽象メソッド public void goOffice(){ System.out.println(name + "が出社しました。"); } public void goHome(){ System.out.println(name + "が帰宅しました。"); } } class SalesMan0901 extends Employee0901 { public SalesMan0901(String name) { super.name = name; } public void work() { System.out.println("営業の仕事を行います。"); } } class Developer0901 extends Employee0901 { public Developer0901(String name) { super.name = name; } public void work() { System.out.println("開発の仕事を行います。"); } } class GeneralManager0901 extends Employee0901 { public GeneralManager0901(String name) { super.name = name; } public void work() { System.out.println("総務の仕事を行います。"); } } public class Sample0901 { public static void main(String[] args) { // 営業部の社員 Employee0901 sm = new SalesMan0901("営業部の社員A"); // 抽象クラスを参照型として使用できます。 // 開発部の社員 Employee0901 dp = new Developer0901("開発部の社員B"); // 抽象クラスを参照型として使用できます。 // 総務部の社員 Employee0901 gm = new GeneralManager0901("総務部の社員C"); // 抽象クラスを参照型として使用できます。 // 出社 sm.goOffice(); dp.goOffice(); gm.goOffice(); // 業務 sm.work(); dp.work(); gm.work(); // 帰宅 sm.goHome(); dp.goHome(); gm.goHome(); } }
・実行結果
C:\dev\java>javac sample0901.java [Enter] C:\dev\java>java sample0901 [Enter] 営業部の社員Aが出社しました。 開発部の社員Bが出社しました。 総務部の社員Cが出社しました。 営業の仕事を行います。 開発の仕事を行います。 総務の仕事を行います。 営業部の社員Aが帰宅しました。 開発部の社員Bが帰宅しました。 総務部の社員Cが帰宅しました。