抽象クラス

この節の要点

  • 抽象的な概念を表現するためのクラスを抽象クラスと呼ぶ。
  • 抽象クラスは少なくとも1つの抽象的な振る舞いを表現する実装がない抽象メソッドを持つ。
  • 抽象クラスはオブジェクトを作ることができない。関係するオブジェクトを作る場合は、継承して子クラスを作り、そのクラスに対してオブジェクトを作る必要がある。

概念(クラス)による階層化を行う上で、概念が抽象的であるがゆえに振る舞いを定義できない場合がよくあります。

例えば、「動物」の概念を想像してみましょう。このとき、「猫」や「犬」は明らかに下位の概念です。ここで、「動物」の普遍的な振る舞いとして、「鳴く」という振る舞いが定義できると思います。すると、下位の概念である「猫」や「犬」では「鳴く」ときの振る舞い、例えば「ニャーニャーと発声する」「ワンワンと発声する」を定義できるはずです。しかし、上位の概念である「動物」において、「鳴く」という具体的な振る舞いを定義することは困難です(図6)。これは、あまりに普遍的な概念であることが原因であると言えます。仮に無理に定義を試みようとしても、せいぜい「発声する」というあまり具体的でない共通した振る舞いを定義できる程度であり、あえて定義したとしてもその振る舞いとして利用する意味が見いだせない、と言ったことが考えられます。

動物の「鳴く」振る舞いと種ごとの振る舞いの違い

図6:動物の「鳴く」振る舞いと種ごとの振る舞いの違い

(この場合は便宜的に典型的な共通認識を「猫」や「犬」として定義していますが、厳密には種として例えば「ヨーロッパヤマネコ」や「タイリクオオカミ」などの下位の概念において振る舞いが定義されるべきです)

プログラムにおいても、継承を前提としたクラス階層を定義する際、定義することが困難な上位クラスが持つ抽象的な振る舞いを、例外的な処理を定義することで無理に実装することは、クラスの凝集度を下げることになります。

こうした抽象的な概念を自然に表現するためのプログラム構造として抽象クラス(Abstract class) があります。

抽象クラスは、抽象的な振る舞いを実現する抽象メソッド(Abstract method) を少なくとも1つ持ちます。この抽象メソッドは 上書きを前提としたメソッド です。抽象クラスを継承したサブクラスにて抽象メソッドの実装を具体的に定義することで上書きすることになります。抽象クラスおよび抽象メソッドはそれぞれアクセシビリティを表す修飾子の次にabstractの修飾子が付けることで表すことができます。図7に抽象クラスの定義(シグネチャ)例、図8に抽象メソッドの定義(シグネチャ)例を示します。

/**
 * 動物を表します。
 */
public abstract class Animal {

	private String name;

	/**
	 * 名前を与えます。
	 */
	public Animal(String name) {

		this.name = name;
	}

	/**
	 * 名前を返却します。
	 * @return 名前。
	 */
	public String getName() {

		return this.name;
	}

	/**
	 * 鳴きます。
	 */
	public abstract void cry();
}
図7:抽象クラスの定義例
/**
 * 鳴きます。
 */
public abstract void cry();
図8:抽象メソッドの定義例

抽象クラスは、自身そのものからオブジェクトを作ることはできません。なぜならば、振る舞いが抽象化されたままで、どのような振る舞いなのか具体的な処理の実装がなされていないためです。また抽象メソッドは実装を持ちません。あくまでどんなオブジェクトを引数として渡す必要があるか、どんなオブジェクトが返却されるのかという情報だけしか定義しません。

よって、抽象クラスの目的は、継承することを前提として下位概念の自然な定義を行うことを目的としています。