0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring DIに感動した話 〜new から解放されるまでの進化〜

0
Posted at

はじめに

Spring の DI(Dependency Injection:依存関係の注入)をちゃんと理解したとき、
「変更に強い設計ってこういうことか」 と素直に感動しました。

  • 実装クラスを直接 new していた頃
  • インターフェースを導入したとき
  • Spring DI で「使う側を一切変えずに差し替えられる」と気づいたとき

この設計の進化の流れを知ったことで、DI のありがたみが腹落ちしたので、整理して記事にします。

背景

  • Java / Spring を勉強中
  • 「DI が大事」「疎結合が良い」と言われるけど、正直ピンときていなかった
  • 小さなサンプルで設計の変化を追ったら理解できた

という前提です。

結論

先にまとめると、学びはこの3点です。

  • new している限り、使う側は実装変更から逃げられない
  • インターフェースは「変更箇所を1か所に減らす」ための道具
  • Spring DI は「使う側を一切触らずに実装を差し替える」仕組み

例題の前提

  • 使われる側:動物(Animal
  • 使う側:動物を実行するクラス(Runner など)

というシンプルな構成で考えます。

パターン1:実装クラスを直接 new する設計

実装

public class Animal {
    public void cry() {
        System.out.println("ワン");
    }
}

public class Runner {
    public void run() {
        Animal animal = new Animal();
        animal.cry();
    }
}

問題点

例えば AnimalDog に変更したくなった場合、

Dog animal = new Dog();
  • 型名
  • クラス名

両方を変更する必要があります。

つまり、

使う側が実装クラスの存在をがっつり知っている 状態です。

パターン2:インターフェースを使った設計

実装

public interface Animal {
    void cry();
}

public class Dog implements Animal {
    public void cry() {
        System.out.println("ワン");
    }
}

public class Runner {
    public void run() {
        Animal animal = new Dog();
        animal.cry();
    }
}

何が良くなったか

DogCat に変えたくなっても、

Animal animal = new Cat();
  • 変更はクラス名だけ
  • 型は Animal のままでOK

これは大きな進歩です。

それでも残る問題

ただし、

  • new Dog() を書いているのは 使う側
  • 実装クラスを切り替えるたびに 使う側の修正が必要

という点は変わっていません。

パターン3:Spring DI を使った設計

実装(アノテーション利用)

@Component
public class Dog implements Animal {
    public void cry() {
        System.out.println("ワン");
    }
}

@Component
public class Runner {

    @Autowired
    private Animal animal;

    public void run() {
        animal.cry();
    }
}

ここで起きていること

  • Runner は 実装クラスを一切知らない
  • new が消えた
  • どの Animal を使うかは Spring が決める

実装を差し替える場合

@Component
public class Cat implements Animal {
    public void cry() {
        System.out.println("ニャー");
    }
}
  • Runner は 一切変更なし
  • アノテーションを付けた実装クラスを差し替えるだけ

これを見たとき、

あ、使う側が完全に守られてるんだ

と腑に落ちました。

なぜこれが嬉しいのか(技術的な話)

  • 依存の向きが「具体」→「抽象」になっている
  • オブジェクト生成の責務を Spring に委譲している

結果として

  • 修正範囲が狭い
  • テストもしやすい
  • 実装差し替えが容易

という状態になります。

ハマりどころ

  • DI = 魔法、と思ってしまう
    → 実態は「new を外に追い出している」だけ

  • インターフェースを使っていないと、DI のありがたみが分かりにくい

  • 小さいサンプルで 段階的に比較しないと理解しづらい

まとめ

  • 最初は new していても問題は見えない
  • インターフェースで「変更箇所を減らす」意味が分かる
  • Spring DI で「変更を使う側から完全に排除できる」と感動する

DI はいきなり理解しようとすると難しいですが、
設計の進化の流れとして見ると、かなり納得感がありました。

同じように「DI よく分からん…」と思っている人の腹落ちに、少しでも役立てば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?