Javaの依存関係の逆転の原則 (DIP) 

# Javaの依存関係の逆転の原則 (DIP) 

## はじめに
Javaの依存関係の逆転の原則 (Dependency Inversion Principle, DIP)は、オブジェクト指向プログラミングにおいて重要な原則の一つです。DIPは、コードの変更をより簡単に行えるようにするため、高位モジュールと低位モジュールの間の依存関係を逆転させることを目的としています。この原則を理解することで、より柔軟で拡張性の高いプログラムを作ることができます。以下の記事はchatGPTによる出力を参考に整形することで作成した記事になります。

## 用語の定義

### 高位モジュール (High-level module)
高位モジュールは、一般的にビジネスロジックを実装しているクラスやモジュールです。高位モジュールは、他の低位モジュールを呼び出すことがありますが、それらの詳細については知りません。

### 低位モジュール (Low-level module)
低位モジュールは、一般的にデータベースや外部APIなどのインフラストラクチャに関連するクラスやモジュールです。低位モジュールは、高位モジュールから呼び出されますが、それらがどのように構築されているかについては知りません。

### 抽象 (Abstraction)
抽象とは、オブジェクトのインターフェイスを定義することです。抽象を使用することで、実装の詳細を知らずにオブジェクトを操作できます。

### 具象 (Concretion)
具象は、抽象の実際の実装です。具象は、抽象のインターフェースを満たす必要があります。

### 依存関係 (Dependency)
依存関係とは、あるオブジェクトが他のオブジェクトに依存する関係のことです。オブジェクトが他のオブジェクトに依存する場合、そのオブジェクトは、その他のオブジェクトが変更された場合に影響を受ける可能性があります。

### 逆転 (Inversion)
逆転とは、従来の依存関係を逆転させることを意味します。従来の依存関係では、低位モジュールが高位モジュールに依存していましたが、逆転

```java
public class UserServiceImpl implements UserService {
    private UserRepository userRepository;

    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public User getUserById(int id) {
        return userRepository.getUserById(id);
    }

    @Override
    public void saveUser(User user) {
        userRepository.saveUser(user);
    }
}
```

この実装では、`UserServiceImpl`が`UserRepository`に依存していますが、`UserRepository`の具体的な実装クラスには依存していません。代わりに、`UserRepository`のインタフェースを宣言した抽象クラスを注入することで、`UserServiceImpl`は`UserRepository`との依存関係を逆転させることができます。

```java
public interface UserRepository {
    User getUserById(int id);

    void saveUser(User user);
}

public class JdbcUserRepository implements UserRepository {
    @Override
    public User getUserById(int id) {
        // JDBCを使用してデータベースからユーザーを取得する
    }

    @Override
    public void saveUser(User user) {
        // JDBCを使用してユーザーをデータベースに保存する
    }
}
```

`JdbcUserRepository`は`UserRepository`インタフェースを実装する具体的なクラスであり、`UserServiceImpl`は`UserRepository`インタフェースを注入することによって`JdbcUserRepository`との依存関係を逆転させることができます。このようにすることで、`UserServiceImpl`は`JdbcUserRepository`の具体的な実装の詳細を知る必要がなくなり、`UserRepository`が提供するメソッドのみに依存することができます。

この例は非常に単純であるため、実際のアプリケーションでは、複数のモジュールやクラスが相互に依存し、それらを管理する必要があります。しかし、DIPを遵守することによって、アプリケーションの柔軟性と拡張性を向上させることができます。

以上が、Javaの依存関係の逆転の原則 (DIP)についての解説です。DIPを理解することは、より良い設計をする上で非常に重要なことであり、将来的に大規模なアプリケーションを開発するために必要なスキルの一つです。

`OrderService` クラスが `OrderRepository` クラスに依存しているため、 `OrderRepository` クラスが変更されると `OrderService` クラスに影響を与えます。しかし、 `OrderService` クラスは `OrderRepository` クラスを必要とするだけでなく、`CustomerService` クラスも必要としています。この場合、`CustomerService` クラスは `OrderService` クラスの高位モジュールであり、`OrderRepository` クラスは低位モジュールであると見なすことができます。高位モジュールが低位モジュールに依存している場合、依存関係は逆転しておらず、依存関係逆転の原則に違反しています。

依存関係を逆転させるために、 `OrderService` クラスは `OrderRepository` クラスを直接参照するのではなく、 `OrderRepository` インターフェースを介して参照する必要があります。これにより、 `OrderRepository` クラスの実装が変更されても、`OrderService` クラスの変更を必要としなくなります。同様に、 `CustomerService` クラスも `CustomerRepository` インターフェースを介して `CustomerRepository` クラスに依存する必要があります。これにより、 `OrderService` クラスと `CustomerService` クラスは、それぞれの高位モジュールであるため、依存関係は逆転しています。

以下は、依存関係逆転の原則に従って再設計された `OrderService` クラスと `CustomerService` クラスの例です。

```java
public interface OrderRepository {
    void save(Order order);
}

public interface CustomerRepository {
    void save(Customer customer);
}

public class OrderServiceImpl implements OrderService {
    private final OrderRepository orderRepository;
    private final CustomerRepository customerRepository;

    public OrderServiceImpl(OrderRepository orderRepository, CustomerRepository customerRepository) {
        this.orderRepository = orderRepository;
        this.customerRepository = customerRepository;
    }

    @Override
    public void placeOrder(Order order) {
        // do some order validation
        // ...

        // save order and customer info
        orderRepository.save(order);
        customerRepository.save(order.getCustomer());
    }
}

public class CustomerServiceImpl implements CustomerService {
    private final CustomerRepository customerRepository;

    public CustomerServiceImpl(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    @Override
    public void createCustomer(Customer customer) {
        // do some customer validation
        // ...

        // save customer info
        customerRepository.save(customer);
    }
}
```

再設計された `OrderServiceImpl` クラスは、 `OrderRepository` インターフェースと `CustomerRepository` インターフェースをコンストラクタで

```java
public interface Database {
    void save(String data);
}
```

ここで定義された`Database`インターフェースは、データベースにアクセスするための一般的なメソッドを定義しています。このインターフェースは、`HighLevelClass`が依存するものの1つであり、具体的な実装には依存していません。つまり、`HighLevelClass`は、`Database`インターフェースを通じてデータベースとやりとりすることができ、その具体的な実装に依存しないため、拡張性が高くなります。

次に、この`Database`インターフェースを実装するクラス`MySQLDatabase`を定義しましょう。

```java
public class MySQLDatabase implements Database {
    public void save(String data) {
        System.out.println("Data saved to MySQL database: " + data);
    }
}
```

ここで、`MySQLDatabase`クラスは`Database`インターフェースを実装しています。`save`メソッドは、`Database`インターフェースで定義されたシグネチャをそのまま実装しています。`HighLevelClass`は、`Database`インターフェースに依存しているため、`MySQLDatabase`クラスの具体的な実装には依存していません。

最後に、`HighLevelClass`クラスを定義し、`Database`インターフェースを使用してデータベースにデータを保存するメソッドを実装します。

```java
public class HighLevelClass {
    private Database database;
    
    public HighLevelClass(Database database) {
        this.database = database;
    }
    
    public void sendData(String data) {
        database.save(data);
    }
}
```

ここで、`HighLevelClass`クラスは、`Database`インターフェースに依存していますが、具体的な実装には依存していません。`HighLevelClass`クラスのコンストラクタで、`Database`インターフェースを実装したオブジェクトを渡すことができます。そして、`sendData`メソッドは、その`Database`オブジェクトを使用してデータを保存することができます。

このように、DIPを適用することで、`HighLevelClass`クラスは、`Database`インターフェースを通じてデータベースとやりとりすることができ、具体的な実装には依存しないため、拡張性が高くなります。また、`Database`インターフェースの具体的な実装には、他のクラスから簡単に切り替えることができるため、柔軟性が高くな

もう一度、コードの修正を行います。まず、`Notifier` インターフェースの定義を以下のように変更します。

```java
public interface Notifier {
    void sendNotification(String message);
}
```

`Notifier` インターフェースは、`NotificationService` クラスから依存されるため、`NotificationService` クラスは依存関係の上位にあり、`Notifier` インターフェースは依存関係の下位にあります。

次に、`NotificationService` クラスの定義を以下のように変更します。

```java
public class NotificationService {
    private Notifier notifier;

    public NotificationService(Notifier notifier) {
        this.notifier = notifier;
    }

    public void sendNotification(String message) {
        notifier.sendNotification(message);
    }
}
```

このようにすることで、`NotificationService` クラスは `Notifier` インターフェースに依存しています。つまり、`NotificationService` クラスは `Notifier` インターフェースを実装したクラスのどれかを受け入れることができます。これによって、`NotificationService` クラスは、具体的な `Notifier` の実装に依存しなくなりました。

次に、`EmailNotifier` クラスを以下のように変更します。

```java
public class EmailNotifier implements Notifier {
    public void sendNotification(String message) {
        // メールを送信する実装
        System.out.println("メールを送信しました：" + message);
    }
}
```

このようにすることで、`EmailNotifier` クラスは `Notifier` インターフェースを実装し、`NotificationService` クラスに依存されることができます。

同様に、`SMSNotifier` クラスを以下のように変更します。

```java
public class SMSNotifier implements Notifier {
    public void sendNotification(String message) {
        // SMS を送信する実装
        System.out.println("SMS を送信しました：" + message);
    }
}
```

これで、`NotificationService` クラスは、`Notifier` インターフェースに依存するように変更され、`EmailNotifier` と `SMSNotifier` クラスは、`Notifier` インターフェースを実装していることが保証されます。依存関係の逆転の原則により、上位の `NotificationService` クラスは下位の `Notifier` インターフェースに依存するようになりました。これにより、`NotificationService` クラスは、`EmailNotifier` と `SMSNotifier` の実装の詳細について知る必要がなくなり、柔軟性と再利用性が向上しました。

## まとめ

依存関係の逆

次に、クライアント側のコードを書いていきます。具体的には、`ElectricPowerSwitch`クラスを作成します。

```java
public class ElectricPowerSwitch {
    public LightBulb lightBulb;
    public boolean on;

    public ElectricPowerSwitch(LightBulb lightBulb) {
        this.lightBulb = lightBulb;
        this.on = false;
    }

    public boolean isOn() {
        return this.on;
    }

    public void press() {
        boolean checkOn = isOn();
        if (checkOn) {
            lightBulb.turnOff();
            this.on = false;
        } else {
            lightBulb.turnOn();
            this.on = true;
        }
    }
}
```

このクラスは、`LightBulb`クラスを依存関係として持ちます。具体的には、`ElectricPowerSwitch`クラスのコンストラクタに`LightBulb`オブジェクトを渡しています。このように、`ElectricPowerSwitch`クラスは`LightBulb`クラスに依存しています。

しかし、この依存関係は、DIPを守っていません。つまり、`ElectricPowerSwitch`クラスは`LightBulb`クラスの具体的な実装に依存しています。そこで、DIPを守るように`ElectricPowerSwitch`クラスを修正します。具体的には、`ElectricPowerSwitch`クラスのコンストラクタに`Switchable`オブジェクトを渡すように変更します。

```java
public class ElectricPowerSwitch {
    public Switchable switchable;
    public boolean on;

    public ElectricPowerSwitch(Switchable switchable) {
        this.switchable = switchable;
        this.on = false;
    }

    public boolean isOn() {
        return this.on;
    }

    public void press() {
        boolean checkOn = isOn();
        if (checkOn) {
            switchable.turnOff();
            this.on = false;
        } else {
            switchable.turnOn();
            this.on = true;
        }
    }
}
```

ここで注目すべき点は、`ElectricPowerSwitch`クラスが依存しているオブジェクトが、`LightBulb`クラスから`Switchable`インターフェースに変更されたことです。つまり、`ElectricPowerSwitch`クラスは`Switchable`インターフェースに依存するようになりました。これにより、`ElectricPowerSwitch`クラスは`Switchable`インターフェースに定義されたメソッドを使用することができるようになり、`LightBulb`クラスの具体的な実装に依存することなく、より柔軟なコードになりました。

以上が、JavaでDIPを実装するための具体的な例です。DIPを守ることにより、コードの柔軟性が向上し、メンテナン

```java
public interface DBConnection {
    void connect();
}

public class MySQLConnection implements DBConnection {
    @Override
    public void connect() {
        System.out.println("Connected to MySQL database.");
    }
}

public class OracleConnection implements DBConnection {
    @Override
    public void connect() {
        System.out.println("Connected to Oracle database.");
    }
}

public class DatabaseManager {
    private DBConnection dbConnection;

    public DatabaseManager(DBConnection dbConnection) {
        this.dbConnection = dbConnection;
    }

    public void connectToDatabase() {
        this.dbConnection.connect();
    }
}
```

この例では、`DBConnection`インタフェースは高位モジュールであり、データベースへの接続を抽象化しています。`MySQLConnection`および`OracleConnection`クラスは低位モジュールであり、実際のデータベースへの接続を実現しています。

`DatabaseManager`クラスは高位モジュールであり、データベースに接続する責任を持ちます。しかし、このクラスは`DBConnection`インタフェースに依存しており、具体的なデータベースに依存していません。これにより、`DatabaseManager`クラスはデータベースへの接続方法を知る必要がありません。

例えば、`DatabaseManager`クラスは次のように使用できます。

```java
DBConnection dbConnection = new MySQLConnection();
DatabaseManager dbManager = new DatabaseManager(dbConnection);
dbManager.connectToDatabase();
```

このコードでは、`DatabaseManager`クラスは`MySQLConnection`クラスのインスタンスを使用してデータベースに接続します。しかし、`DatabaseManager`クラスは`MySQLConnection`クラスに依存していないため、必要に応じて別のデータベースに接続することができます。

例えば、`OracleConnection`クラスを使用する場合は、次のようにコードを変更することができます。

```java
DBConnection dbConnection = new OracleConnection();
DatabaseManager dbManager = new DatabaseManager(dbConnection);
dbManager.connectToDatabase();
```

このように、`Dependency Inversion Principle`は、高位モジュールが低位モジュールに直接依存することなく、抽象に依存することを推奨しています。これにより、コードの柔軟性、拡張性、保守性が向上します。