👨‍💻

Dependency Injection: 依存性の注入?

2024/10/06に公開

DI(Dependency Injection、依存性注入)

DI(依存性注入)は、オブジェクト間の依存関係を外部から注入して管理するデザインパターンです。Springでは、DIコンテナを使ってオブジェクトの生成と依存関係の解決を自動でやってくれます。

依存性とは

dependencyを「依存性」と訳さず、オブジェクト注入と解釈する

つまり、言い換えると
与えられたオブジェクトと渡す
ってことかな?

メリット

  • 疎結合: オブジェクト同士の結びつきがゆるくなります。これにより、特定の実装に縛られない設計ができて、コードの変更や拡張がしやすくなります。
  • テストが楽: 依存するオブジェクトをモックに置き換えてテストできるので、ユニットテストが簡単になります。外部の影響を受けずにテストできるので、バグも早めに見つかります。
  • 再利用性と柔軟性: コンポーネントがインターフェースや抽象クラスに依存することで、いろんな場面で再利用しやすくなります。新機能を追加する際も、大きなコード変更は不要です。
  • 可読性と保守性: 依存関係がはっきりするので、コードが読みやすくなります。また、ある部分を変更しても他に影響しないので、メンテナンスも楽です。

デメリット

  • 学習コスト: 初心者にはちょっと難しい?
  • オーバーヘッド: 小さいプロジェクトには向かないことがあります。依存関係を解決するための負担がビルド時や実行時にかかるかも?

SpringのDI(依存性注入)を車に例えると

従来の方法

従来では、車クラスがエンジンクラスを直接作ります。例えば、「new Engine()」という感じでコードを書きます。これだと車は特定のエンジンに強く依存してしまい、エンジンを変えるのが大変

public class Engine {
    public void start() {
        System.out.println("エンジン始動");
    }
}

public class Car {
    private Engine engine;

    public Car() {
        this.engine = new Engine(); // 直接Engineをインスタンス化
    }

    public void drive() {
        engine.start();
        System.out.println("車が走り出しました");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        car.drive();
    }
}

依存性注入を使った方法

DIを使うと、エンジンを直接作らずに車を作るときに外部からエンジンを「注入」します。車のコンストラクタやメソッドでエンジンのインスタンスを受け取ることで、どんなタイプのエンジンでも柔軟に対応できる。

public interface Engine {
    void start();
}

public class GasolineEngine implements Engine {
    @Override
    public void start() {
        System.out.println("ガソリンエンジン");
    }
}

public class ElectricEngine implements Engine {
    @Override
    public void start() {
        System.out.println("電気モーター");
    }
}

public class Car {
    private Engine engine;

    @Autowired // SpringのDIアノテーション
    public Car(Engine engine) {
        this.engine = engine;
    }

    public void drive() {
        engine.start();
        System.out.println("車がうごいた!");
    }
}

@Configuration
public class CarConfig {
    @Bean
    public Engine engine() {
        return new GasolineEngine(); // または new ElectricEngine()
    }

    @Bean
    public Car car(Engine engine) {
        return new Car(engine);
    }
}

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(CarConfig.class);
        Car car = context.getBean(Car.class);
        car.drive();
    }
}

DIによる利点

  • 柔軟性: エンジンを変えたい時も簡単に異なるエンジンを注入できる。
  • テストが楽: テスト時にはモックオブジェクトを注入して、本物のエンジンクラスに頼らずテストできちゃう。
  • 再利用性: 車クラスは特定のエンジンクラスに縛られないので、いろんな設定で再利用できます。

こんな感じで、DIは車とその部品(エンジン)の関係を柔軟で効率的に管理するためのパターン。

https://ja.wikipedia.org/wiki/依存性の注入
https://qiita.com/hshimo/items/1136087e1c6e5c5b0d9f
参考にした記事です。 ありがとうございます

Discussion