読者です 読者をやめる 読者になる 読者になる

【Java】今更ながら,抽象クラスとインターフェースについて考える事になった件

今まで大学の課題等で作って来たプログラムが小規模だったからか
自分が無知だったかは置いといて,

・抽象クラスとinterfaceについて

改めて勉強し直しました.
今回は,そのまとめです.

・2つに共通する部分

基本的には,そのクラスを継承(または実装)させることで,意味をなすこの2つ,
サブクラスの必須の実装を制限する効果を持っています.
これらを使う場面は

  • どのクラスにも共通する実装部分がある時
  • 機能としては分かっているが,実装の中身までは分からない時
  • 既存のクラスを拡張して使いたい時

が挙げられます.

例えば電卓
足し算と引き算の実装を以下の様にしたとします.

public class Add{
	double getAdd(double num1, double num2){
		return num1+num2;
	}
}

public class Sub{
	double getSub(double num1, double num2){	
		return num1 - num2;
        }
}

この2つの関数から呼び出しを行う時
"getAdd"や"getSub"といったメソッド名を把握しておかなければならないという問題が発生してしまいます.
さらに,これにかけ算を追加したいときは,"getMul"などといった様になると考えられます.
これを呼び出して使うとなると非常に分かりにくい.
何より,一回メソッド名を変更すると複数箇所変更する必要が出てくるのが最大の問題点となります.

これらの問題を解消する為に,抽象クラスやインターフェースを使って次のように実装してみました.

・抽象クラスを使った実装
abstract  class Operator{
	abstract  double getAns(double num1, double num2);
}

public class Add extends Operator{
	@Override
	double getAns(double num1, double num2){
		return num1 + num2;
	}
}

public class Sub extends Operator{
	@Override
	double getAns(double num1, double num2){	
		return num1 - num2;
}
・インターフェースを使った実装
interface Operator{
	double getAns(double num1, double num2);
}

public class Add implements Operator{
	double getAns(double num1, double num2){
		return num1 + num2;
	}
}

public class Sub implements Operator{
	double getAns(double num1, double num2){	
		return num1 - num2;
}


どちらの計算結果も”getAns”というメソッド名で呼び出すことが出来るようになりました.
これによって,他から呼び出される時に,特に実装内容を知らずにコーディングが出来るようになったというわけです.
これによって拡張性の向上がはかれるようになりました.
一見2つのプログラムに違いが無いように見えますが,次は,これらの違いについて説明して行きたいと思います.

・抽象クラスの特徴

  1. インスタンスを生成することは出来ない
  2. このクラスをスーパークラスとして実装される
  3. このクラスのサブクラスは必ず抽象クラスのメソッドを実装する必要がある
  4. サブクラスは1つしか抽象クラスから継承できない
  5. 抽象クラス内で,通常のメソッドを実装することが出来る

・抽象クラスの宣言

//抽象クラスの宣言
abstract class クラス名{
	//メソッドの宣言
	abstract 戻り値 メソッド名();
}

・インターフェースの特徴

  1. インターフェースを実装(implements)したクラスは必ずインターフェース内のメソッドを全て実装する
  2. インターフェース内で,通常のメソッドは実装できない
  3. 複数のインターフェースを実装させることが出来る
  4. 変数は全てstatic finalで宣言される(定数として扱われる)

・インターフェースの宣言

//抽象クラスの宣言
interface クラス名{
	//メソッドの宣言
	戻り値 メソッド名();
}

インターフェース内で実装される内容は,必ず抽象メソッドなのでabstractは記述する必要はない.*1

・今日のまとめ

抽象クラスとインターフェースの使い分け

・抽象クラス

 デフォルトの処理を与えておきたい時
 is-a関係(譲渡)を表現したい時

・インターフェース

 クラス内を知らなくてもクラスを扱えるようにする為の約束事
 has-a関係(集約)を表現したい時

どちらも,必ずプログラムを組むのに必要なものではないですが,
これがあった方が拡張性や保守性を高めることが出来るという話しでした.

*1:書かない場合,public abstractがデフォルトで付きます.