🖥️

プログラミング自己主導学習 [Java] インターフェースの定義と役割

に公開

インタフェース(Interface)とは?

抽象メソッド(実装されていないメソッド)の集合で、クラスが特定の機能を

具現するよう強制する役割をする。

インターフェイスを使用すると、オブジェクト間の結合度を下げ、多形性をサポートして柔軟なコード作成が可能である。

インターフェースの主な役割

ポリモーフィズム(多態性)の提供

インターフェースを使用すると、1つのインターフェースを複数のクラスが異なる方法で実装できるため、多態性を容易に活用できます。

例)List インターフェースには ArrayList、LinkedList などの多様な実装が存在し、インターフェースを通じてオブジェクトを扱うことができます。

import java.util.*;

public class ListExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();  // List インターフェースの使用
        list.add("リンゴ"); list.add("バナナ"); list.add("チェリー");

        printList(list);  // 実装クラスを意識せずに同じ方法で使用可能
    }

    public static void printList(List<String> list) {
        list.forEach(System.out::println);
    }
}

疎結合(Loose Coupling)を実現し、保守性を向上

インターフェースを活用すると、実装クラスに直接依存せずにインターフェースを通じてオブジェクトを扱うことができ、保守性が向上します。

例えば、異なる決済方法をインターフェースで統一することで、実装を意識せずに決済方法を簡単に変更できます。

// インターフェース定義
public interface Payment { void pay(int amount); }

// 実装クラス
class KakaoPay implements Payment { public void pay(int amount) { System.out.println("KakaoPay 決済: " + amount); } }
class PayPal implements Payment { public void pay(int amount) { System.out.println("PayPal 決済: " + amount); } }

public class PaymentTest {
    public static void main(String[] args) {
        Payment payment = new KakaoPay();  // 簡単に決済方式を変更可能
        payment.pay(10000);  // KakaoPay 決済: 10000
    }
}

多重継承の効果を提供

Java は単一継承のみをサポートしますが、インターフェースを使用すると、複数のインターフェースを同時に実装でき、多重継承に似た効果を得ることができます。

例えば、Vehicle インターフェースと Engine インターフェースを定義し、Car クラスで両方を実装することで、両方の特性を持つクラスを作成できます。

public interface Vehicle { void move(); }
public interface Engine { void start(); }

class Car implements Vehicle, Engine {
    public void move() { System.out.println("車が移動!"); }
    public void start() { System.out.println("エンジン始動!"); }
}

public class MultiInheritanceTest {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.start();  // エンジン始動!
        myCar.move();   // 車が移動!
    }
}

開発標準と一貫性の維持

大規模なプロジェクトでは、共通のインターフェースを定義することで、一貫した構造を維持できます。

全てのクラスで同じ方法で使用できるため、コードの一貫性を確保し、チームメンバー間のコラボレーションを容易にし、保守性を向上させます。

public class Student implements Comparable<Student> {
    String name; int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public int compareTo(Student other) { return Integer.compare(this.score, other.score); }

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student("Alice", 90), new Student("Bob", 80));
        Collections.sort(students);  // スコア基準でソート
    }
}

テストの容易性向上

インターフェースを使用すると、モック(Mock)オブジェクトを活用して単体テストを容易に実施できます。

例えば、データベースと接続された UserRepository を直接テストすると環境によって結果が異なる可能性がありますが、UserRepository インターフェースを用意し、モック実装を利用すれば、実際のデータベースなしでもテストが可能になり、テストコードの作成が容易になります。

Discussion