抽象クラス vs インターフェース
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 38/87。
ここまでで abstract クラスとインターフェースの both を理解したところで、どちらを使うべきかという一般的な疑問が生じます。一方を他方より優先して使うべきかは、何をモデル化しようとしているかによって決まります。
共有された state または behavior を持つ共通の基盤を classes が共有する場合は、abstract class を使用します。abstract class には instance variables、constructor、abstract メソッドと concrete メソッドの組み合わせを含めることができます。
public abstract class Animal {
protected String name; // 共有状態
public Animal(String name) {
this.name = name;
}
public void sleep() { // 共有振る舞い
System.out.println(name + " is sleeping");
}
public abstract void makeSound(); // 実装する必要がある
}無関係なクラス間で共有できる機能を定義したい場合は、インターフェースを使用します。インターフェースは、オブジェクトが何であるかではなく、何ができるかに重点を置きます。
public interface Flyable {
void fly();
}
// 無関係なクラスがこの機能を共有できる
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }簡単に比較してみましょう:
| 機能 | Abstract Class | インターフェース |
|---|---|---|
| インスタンス変数 | はい | 定数のみ |
| コンストラクター | はい | いいえ |
| 多重継承 | いいえ(単一の extends) | はい(複数の implements) |
| アクセス修飾子 | 任意 | 公開のみ(abstract メソッドの場合) |
実践的な指針:abstract メソッドだけを持ち、状態を持たない abstract class を作成していることに気づいたら、インターフェースのほうが適している可能性が高いでしょう。
チャレンジ
簡単abstract クラスとインターフェースをいつ使うべきかを demonstrates する vehicle system を構築しましょう。abstract クラスを通じて共通の state と behavior を共有する vehicles を model 化し、インターフェースを通じて optional な capability を追加します。
コードを五つのファイルに分けて整理します。
Vehicle.java: すべての vehicles の基盤となる abstract class を Create します。すべての vehicle にはbrandfield (String) とyearfield (int) があります。両方の fields を初期化する constructor、それぞれの getter methods、そして String を返す abstract methodstartEngine()を含めます。また、[brand] ([year])を返す concrete methodgetInfo()も追加します。これは abstract class の perfect な use case です。vehicles は state (brand, year) と一部の behavior (getInfo) を共有しますが、それぞれ異なる方法で engine を start します。Convertible.java: roof を convert できる vehicles のための interface を Declare します。この capability は vehicle が何であるか(is)には tied していません。特定の vehicles がcan doことです。String を返す二つの methods、openRoof()とcloseRoof()を Declare します。Car.java:Vehicleを extends し、Convertibleを implements する class を Create します。Car には追加のnumDoorsfield (int) があります。superを使用して inherited fields を初期化します。startEngine()は[brand] car engine startedを返すように Implement します。openRoof()は[brand] roof openingを返し、closeRoof()は[brand] roof closingを返すように Implement します。Motorcycle.java:Vehicleを extends しますが、Convertibleは implements しない class を Create します。motorcycles には roofs がありません。Motorcycle にはhasSidecarfield (boolean) があります。startEngine()は[brand] motorcycle engine roaringを返すように Implement します。Main.java: すべてをまとめて、abstract classes と interfaces の違いを showcase します。四つの inputs、つまり car の brand、car の year、motorcycle の brand、motorcycle の year を受け取ります。4 doors の Car と、sidecar なしの Motorcycle を Create します。まず、両方の vehicles に対して
getInfo()を print し、共有される abstract class の behavior を demonstrate します。これらは両方とも Vehicle からこれを inherit します。次に、それぞれのstartEngine()の result を print します。それぞれの vehicle type がこれを異なる方法で Implement していることに注目してください。最後に、interface の capability を demonstrate します。
Convertibleを implements するのは Car だけなので、car に対してのみopenRoof()を call して print し、その後closeRoof()を call して print します。
四つの inputs、つまり car brand (String)、car year (int)、motorcycle brand (String)、motorcycle year (int) を受け取ります。
出力は合計 six lines になるはずです。両方の vehicles が abstract class の state と getInfo() method を共有しますが、convertible capability を持つのは Car だけであることに注目してください。これは、それぞれの approach をいつ使うべきかを illustrates しています。
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 入力を読み取る
String carBrand = scanner.nextLine();
int carYear = scanner.nextInt();
scanner.nextLine(); // 改行を消費する
String motorcycleBrand = scanner.nextLine();
int motorcycleYear = scanner.nextInt();
// TODO: 4ドアのCarを作成する
// TODO: サイドカーなしのMotorcycleを作成する (false)
// TODO: 両方の車両のgetInfo()を出力する(共有された抽象クラスの振る舞いを示す)
// TODO: 両方の車両のstartEngine()を出力する(異なる実装を示す)
// TODO: 車のみのopenRoof()とcloseRoof()を出力する(インターフェースの機能を示す)
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造6インターフェースと抽象クラス
インターフェース入門インターフェースの実装複数インターフェースの実装インターフェースのデフォルトと静的メソッド抽象クラス vs インターフェース関数型インターフェースまとめ - 決済システム自分で練習してみよう: Javaオンラインコンパイラ