はじめに
アホでもわかるように解説してみるテスト。
あらゆる方向で説明してみる。
大雑把にまとめると「依存していた部分を、外から注入すること」です。
勘違い、間違いが沢山ありそうなので、是非ご指摘を!
登場人物 (用語)
- 依存性の注入 (日本語)
- Dependency Injection (英語)
- DI (Dependency Injectionの略語)
依存関係を設定ファイル等で定義してよろしくやってくれる「DIコンテナ」については書いておりません!
何が問題なの?
クラス内などで固定化されたものがあると
- 柔軟性がない
- テストしにくい
解決方法
「依存している部分を外から注入する」
DIにおける「依存性」と「注入」の意味
-
依存性
(大雑把に)とあるクラスに、固定の定数、変数、インスタンスが入っちゃっている状態
つまりそのクラスは、その定数、変数、インスタンスに依存している -
注入
そのクラスの外から定数、変数、インスタンスをあるクラスにぶちこむこと
注意) クラスだけに限らないという話もある。けど、ほとんどの場合クラスになるので、以下もクラスにする
つまり、何が何に依存している?
とあるクラスが、固定した他の(定数、変数、クラスなど)に依存している
どうしたいの?
依存性をなくすために、動的に動作を注入しようぜ! ってこと
つまり、あるクラス内の決め打ち定数、変数、インスタンスを排除して、外から注入することで、動的に動作を変えられるようにする
依存していると、何が嫌なの?
- 外から動的に動作を変更できないので、テストしづらい
- 決め打ちなので、柔軟性がなくカスタマイズしにくい
具体的にどう困るの?
あるクラスだけテストしたいのに
- 中に別のクラスが入っているとテストしにくい
- テストに時間がかかるメソッドが中にあってテスト終了に時間がかかる
で、結局どうしろっての?
- 引数で、クラスや変数を外から受け取れるようにする
車で例えてみる
結論から言うと、
「依存性の高い車は、特定のメーカーのパーツで固定されちゃっていて、カスタマイズできない車」
ということになる
依存性の高い車の場合
車が以下のパーツできている
- ホンダのエンジン
- ブリジストンのホイール
- パナソニックのバッテリー
しかし、全部のパーツが半田ゴテでくっつけちゃってあるので、他のメーカーのバッテリーに変更ができない!
テストの視点から例えると、バッテリーだけの消耗テストがしたい場合
- バッテリーだけ取り出して放電、充電の繰り返しテストができない
- 配線も半田ゴテでくっつけちゃっているので、車のランプをつけたり、エンジンをつけて放電・充電をしなくてはいけない!
つまり、全体としてしかテストできない!!
依存性の低い車の場合
パーツをどのようにもカスタマイズできる車
他社のバッテリーを入れる(注入する)ことができる
コードで説明
以下が、依存性の高い、車クラス
class Car {
private Engine en = new HondaEngine();
private Wheel wh = new BridgestoneWheel();
private Battery bt = new PanasonicBattery();
// ...
}
車のパーツが決め打ちである。
Carクラスをテストしたい場合や他のEngineクラスに変更したい場合、コードを書き換えないとできないことになって面倒!
依存性の低い(注入している)コードは…
誰か書いて下さい! (他人に依存)
基本的にこんな感じでコーディングすると思います。
- Engine, Wheel, Battery クラスを作る
- 上記を継承(Javaなら implements)して、各メーカーのクラスを作る (PanasonicBattery()など)
- Carクラスにセッターを作る (setBattery() など)
- setBattery(new PanasonicBattery()) で注入
DIなコードは、以下が参考になります。
GT's Blog: Dependency Injection with Java Spring IoC, A Complete Example
インジェクションの方法
- コンストラクター・インジェクション
- セッター・インジェクション
DIのメリット
以下の記事によるメリット
(2/3)記者の眼 - Java開発を変える最新の設計思想「Dependency Injection(DI)」とは:ITpro
・ソフトウエアの階層をきれいに分離した設計が容易になる
・コードが簡素になり、開発期間が短くなる
・テストが容易になり、「テスト・ファースト」による開発スタイルを取りやすくなる
・特定のフレームワークへの依存性が極小になるため、変化に強いソフトウエアを作りやすくなる(=フレームワークの進化や、他のフレームワークへの移行に対応しやすくなる)
デメリット
- はじめに工数がかかる場合が多いと思われる
クラスをたくさん作るので(大抵の場合) - プログラムの実行スピードが遅くなる可能性が高い
- クラスやファイルが沢山できる
他にもデメリットがあれば、教えて下さい
もっと例えが欲しい?
女の子に例えると
ある女の子が固定の男性に依存している場合、その依存性を排除して、外部から男の子を注入できるようにしようという願望です。
メリットとしては
- 特定の男性への依存性が極小になるため、変化に強い女の子が作りやすくなります。(=男性の進化や、他の男性への移行に対応しやすくなる)
参考URL
-
design patterns - What is dependency injection? - Stack Overflow
http://stackoverflow.com/questions/130794/what-is-dependency-injection -
GT's Blog: Understanding Dependency Injection and its Importance, A tutorial
http://ganeshtiwaridotcomdotnp.blogspot.jp/2011/05/understanding-dependency-injection-and.html