it

インターフェースとクラスの違いは?抽象クラスとの比較も!(オブジェクト指向:実装:継承:UMLクラス図:定義など)

当サイトでは記事内に広告を含みます

プログラミングを学んでいると、「インターフェース」と「クラス」の違いがわからなくなることはないでしょうか。さらに「抽象クラス」も登場すると、どれをどう使い分ければいいのか迷ってしまう方も多いでしょう。

本記事では、インターフェースとクラスの違い・抽象クラスとの比較・オブジェクト指向での使い分けをわかりやすく解説していきます。

インターフェースとクラスの最大の違いは「実装を持つかどうか」

それではまず、インターフェースとクラスの根本的な違いについて解説していきます。

クラスはデータ(フィールド)と処理(メソッド)の実装をまとめた設計図です。一方、インターフェースは「何ができるか」という仕様だけを定義したもので、原則として処理の実装を持ちません。

クラスがインターフェースを「実装(implement)」することで、インターフェースで定義されたメソッドを必ず持つことが保証されます。これがオブジェクト指向プログラミングにおける「契約」の考え方です。

インターフェースは「何をするか(What)」を定義し、クラスは「どのようにするか(How)」を実装します。この役割分担を意識することで、インターフェースとクラスの使い分けが自然と理解できるようになります。

クラスの基本的な特徴

クラスはオブジェクト指向プログラミングの基本単位です。フィールド(変数)・コンストラクタ・メソッドを持ち、インスタンスを生成して使います。

クラスは他のクラスを「継承(extends)」することで、親クラスの機能を引き継ぎながら新たな機能を追加できます。ただし、多くの言語では1つのクラスしか継承できない「単一継承」の制約があります。

インターフェースの基本的な特徴

インターフェースはメソッドのシグネチャ(名前・引数・戻り値の型)のみを定義し、具体的な処理は実装クラスに委ねます。

クラスと異なり、1つのクラスが複数のインターフェースを実装できる「多重実装」が可能です。これにより、単一継承の制約を補いながら柔軟な設計が実現できます。

比較項目 クラス インターフェース
実装の有無 あり 原則なし
インスタンス生成 可能 不可
継承・実装数 単一継承 複数実装可能
フィールド 持てる 原則持てない
主な用途 処理の実装・再利用 仕様の定義・型の統一

Javaでのインターフェースとクラスの書き方

Javaを例にインターフェースとクラスの基本的な書き方を確認しましょう。


// インターフェースの定義
interface Grindable {
    void grind(); // メソッドのシグネチャのみ定義
}

// クラスがインターフェースを実装
class CoffeeBeanGrinder implements Grindable {
@Override
public void grind() {
System.out.println(“コーヒー豆を挽いています”);
}
}

// 実行
public class Main {
public static void main(String[] args) {
Grindable grinder = new CoffeeBeanGrinder();
grinder.grind();
}
}

# 出力結果:コーヒー豆を挽いています

抽象クラスとインターフェースの違い

続いては、抽象クラスとインターフェースの違いと使い分けについて確認していきます。

抽象クラスはインターフェースとクラスの中間的な存在です。「抽象メソッド(実装なし)」と「具体的なメソッド(実装あり)」の両方を持てる点が特徴です。

抽象クラスの特徴と使い方

抽象クラスはabstractキーワードで定義し、インスタンスを直接生成することはできません。サブクラスに継承させて抽象メソッドをオーバーライドして使います。


// 抽象クラスの定義
abstract class Vehicle {
    String name;

```
Vehicle(String name) {
    this.name = name;
}

// 抽象メソッド(サブクラスで実装必須)
abstract void move();

// 具体的なメソッド(共通処理)
void showName() {
    System.out.println("乗り物名:" + name);
}
```

}

// サブクラスで抽象メソッドを実装
class Bicycle extends Vehicle {
Bicycle() {
super(“自転車”);
}

```
@Override
public void move() {
    System.out.println("ペダルを漕いで進む");
}
```

}

public class Main {
public static void main(String[] args) {
Vehicle v = new Bicycle();
v.showName();
v.move();
}
}

# 出力結果:乗り物名:自転車

# 出力結果:ペダルを漕いで進む

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

抽象クラスとインターフェースはどちらも「実装を強制する仕組み」ですが、使い分けのポイントは以下のとおりです。

比較項目 抽象クラス インターフェース
実装の共有 可能(共通処理を持てる) 原則不可
多重継承・実装 単一継承のみ 複数実装可能
フィールド 持てる 原則持てない
向いているケース 共通の処理・状態を持たせたいとき 型の統一・多重実装が必要なとき

「共通の処理や状態を持たせたいなら抽象クラス、型の統一や多重実装が必要ならインターフェース」という基準で選ぶとスムーズです。

UMLクラス図での表現方法

UMLクラス図では、インターフェースは「<>」というステレオタイプで表記します。クラスからインターフェースへの実装関係は破線矢印で、継承関係は実線矢印で表現します。

抽象クラスはクラス名をイタリック体で表記するか、「{abstract}」という制約を付けて表現します。UMLでの表記を理解しておくことで、設計書の読み書きがスムーズになるでしょう。

オブジェクト指向設計でのインターフェースの活用

続いては、実際の設計においてインターフェースをどのように活用するかを確認していきます。

依存性の逆転原則とインターフェース

オブジェクト指向設計の原則のひとつに「依存性の逆転原則(DIP)」があります。これは具体的な実装クラスではなく、インターフェースに依存するように設計する考え方です。

インターフェースを介することで、実装クラスを差し替えてもコードの変更が最小限で済みます。テストの際にモック(擬似オブジェクト)を使いやすくなるという利点もあります。

複数インターフェースの実装例

Javaでは1つのクラスが複数のインターフェースを実装できます。以下はその例です。


interface Flyable {
    void fly();
}

interface Swimmable {
void swim();
}

// 複数のインターフェースを実装
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println(“アヒルが飛んでいます”);
}

```
@Override
public void swim() {
    System.out.println("アヒルが泳いでいます");
}
```

}

public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.fly();
duck.swim();
}
}

# 出力結果:アヒルが飛んでいます

# 出力結果:アヒルが泳いでいます

インターフェースを使うメリットまとめ

インターフェースを活用することで得られる主なメリットは以下のとおりです。

まず、実装を強制することでチーム開発における仕様の統一が図れます。次に、複数のインターフェースを実装できるため設計の柔軟性が高まります。さらに、実装クラスを差し替えやすくなることで、テストのしやすさや保守性の向上にもつながります。

まとめ

本記事では、インターフェースとクラスの違い・抽象クラスとの比較・オブジェクト指向設計での活用方法について解説しました。

クラスは処理の実装を持つ設計図であり、インターフェースは仕様のみを定義したものです。抽象クラスはその中間で、共通処理と抽象メソッドの両方を持てます。使い分けの基準は「共通の処理を持たせたいなら抽象クラス、型の統一や多重実装が必要ならインターフェース」です。

インターフェースを適切に活用することで、柔軟性・保守性・テストのしやすさが向上します。オブジェクト指向設計の理解を深めながら、場面に応じた使い分けを身につけていきましょう。