はじめに
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();
}
}
問題点
例えば Animal を Dog に変更したくなった場合、
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();
}
}
何が良くなったか
Dog を Cat に変えたくなっても、
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 よく分からん…」と思っている人の腹落ちに、少しでも役立てば嬉しいです。