9 章: 抽象クラス

抽象クラスは文字通り抽象的存在のクラスであり, 具体的な処理はこれを継承したクラスに記述させる. 抽象クラスの存在意義は複数のクラスに対して共通性を持たせることであり:

クラス設計においてとても重要な役割を担っている

抽象クラスの特徴

抽象クラスの特徴として, 具象クラス (通常のクラス) との違いを挙げる.

  1. 抽象メソッドを定義することができる:
抽象メソッドとは, 実際の処理を自身にではなく, 子クラスに記述させるためのメソッド. この抽象メソッドを記述できることが, 抽象クラスの最大の特徴. 抽象クラス を継承したクラスは, この抽象メソッドを必ず [オーバーライド] しなければい (オーバーライドしないとコンパイルエラーとなる)
  1. 抽象クラス単体でインスタンスを生成することはできない:
抽象メソッドを定義している. つまり, 実際の処理を記述していないためであるから, 当然インスタンスを生成して使用することはできない.

抽象クラスおよび抽象メソッドの書式

抽象クラスおよび抽象メソッドの書式は次の通りである:

abstract class クラス名{
  abstract 戻り値 メソッド名 (引数リスト);
}

注意:

抽象クラスには通常のメソッドも記述できる. また抽象メソッドは省略可能であるが, 抽象クラスの意味がないと考える.

抽象クラスの設計

抽象クラスについては, 実際の使用例を見たほうが理解しやすいと思うので, 例として, ある会社の社員クラスの設計を考えてみる.

社員クラスの条件は次の通り:

1. 午前 9 時に出社する
2. 会社には, 営業部, 開発部, 総務部がありそれぞれ, 仕事を開始する
3. 午後 6 時に帰宅する.

このとき社員クラスを次のように考えたとすると.

_images/java-abstract011.gif

これでは働くという処理に対して, 営業部, 開発部, 総務部の区別をつけることができない. これをどう解決するか? 次の2つが考えられる:

1. [営業部社員クラス], [開発部社員クラス], [総務部社員クラス] を個別に作成する.
2. [働く()] に引数を持たせて, その引数の値で営業部, 開発部, 総務部を判別し処理を分ける. もしくは [働く()] の代わりとして各部署にメソッドを作成 (例えば, 営業ワークメソッド, 開発ワークメソッドなど) して呼び分ける.

この2つの解決方法に体するメリットとデメリットとしては, 次のようなことが挙げられる.

各解決手法のメリットとデメリット

_images/abstract91.gif

どちらを選択したらよいでしょうか??

実はこのような時に抽象クラスを使用すると, その威力を発揮してくれる.

社員クラスを抽象クラス, そして [働く()] を抽象メソッドとして次のような構成を考える.

_images/java-abstract021.gif

これにより2つの解決方法で, その両方のメリットを担保しつつ, それぞれのデメリットが解消されているのがわかる:

1. 各部署の社員クラスを区別に作成するが, 社員クラスを継承することで共通メソッドは記述せずに使用できる. (1 のメリット担保, 1, 2 のデメリット解消)
2. 抽象メソッドである [働く()] の実装は保障される. (1 のデメリット解消)
3. 各部署の社員クラスは, 親クラスである [社員クラス型] で統一した呼び出し方ができる. (2 のメリット担保)

このように抽象クラスはクラスの構成を考える上でとても有効な手段となることが理解できると思う.

Sample0901.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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();
    }
}

上記のプログラムの実行結果:

[wtopia 9]$ java Sample0901
営業部の社員 Aが出社した
開発部の社員 Bが出社した
総務部の社員 Cが出社した
営業の仕事を行う
開発の仕事を行う
総務の仕事を行う
営業部の社員 Aが帰宅した
開発部の社員 Bが帰宅した
総務部の社員 Cが帰宅した

Table Of Contents

Previous topic

8 章: 継承

Next topic

10 章: インタフェース