こちらを読むと
- オブジェクト指向のDependency Injection(DI) パターンの概要が分かります。
- 記事の所要時間は10分です
結論
- 柔軟性のある設計をするために、Dependency Injectionを普段から意識することが重要!
以降、詳細を解説していきます。
Dependency Injection(DI)とは
- オブジェクト指向の設計技法(デザインパターン)の1つです
- オブジェクトを「生成するクラス」と「使用するクラス」を分けます
- 例えば、クラスA→クラスBへ依存(has-a)関係がある場合に、クラスCがBを生成してAに渡します
DIではない例
まずは、DIを使っていない例について説明します。以下のコードをご覧ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/** * 計算をするクラス。 */ public class Calculator { // 結果を出力するクラス private Printer printer; /** * コンストラクタ。 */ public Calculator() { this.printer = new StandardPrinter(); } /** * 加算結果を出力。 */ public void add(int a, int b) { printer.print(a + b); } /** * 乗算結果を出力。 */ public void mul(int a, int b) { printer.print(a * b); } } |
こちらは計算をするクラスで、加算結果を出力するメソッドと、乗算結果を出力するメソッドをもっています。
StandardPrinterクラスのprintメソッドは、標準出力を出す機能があると考えてください。
DIを使わないと修正範囲が大きくなる
ここで、標準出力ではなく、ファイル出力に変更する必要が出てきた場合、どうなるでしょうか。
ここで、以下の継承関係があるとします。(Printerはインタフェース)
ファイル出力をするクラス:メソッドを、FilePrinter:printとすると、以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/** * 計算をするクラス。 */ public class Calculator { // 結果を出力するクラス private Printer printer; /** * コンストラクタ。 */ public Calculator() { this.printer = new FilePrinter(); } /** * 加算結果を出力。 */ public void add(int a, int b) { printer.print(a + b); } /** * 乗算結果を出力。 */ public void mul(int a, int b) { printer.print(a * b); } } |
Calculatorクラスの内部で、FilePrinterクラスを生成する必要がありますね。
このクラスだけだとまだ良いかもしれませんが、同じように標準出力を使って出力しているクラスが100個あったとすると、それらをすべて修正する必要が出てきます。
DIを導入すれば、これを解決することができます!
DIの例
以下が、DIの例になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/** * 計算をするクラス。 */ public class Calculator { // 結果を出力するクラス private Printer printer; /** * コンストラクタ。 */ public Calculator(Printer printer) { this.printer = printer; } /** * 加算結果を出力。 */ public void add(int a, int b) { printer.print(a + b); } /** * 乗算結果を出力。 */ public void mul(int a, int b) { printer.print(a * b); } } |
上のコードとほぼ同じですが、コンストラクタでPrinterクラスを渡して、メンバー変数にセットしているのがポイントです。
このように使用するオブジェクトを外部から与える手法がDependency Injection(DI)です。
こうすれば、標準出力からファイル出力に変更したとしても、Calculatorクラスは修正する必要がありません。
DI考察
DIを必ずしも使わなければならないわけではありませんが、常に意識して、外部からオブジェクトを切り替えられないか検討する習慣は付けておいた方がよいと思います。
DIに限らずインタフェースを使うことを心掛け、必要な時がきたら、オブジェクトの変更により処理をごっそり入れ替えることが重要です。
まとめ
- オブジェクト指向のDependency Injection(DI) パターンの概要が分かりました。
- 柔軟性のある設計をするために、Dependency Injectionを普段から意識することが重要!
Reference
Effective Java 第3版
https://www.amazon.co.jp/dp/4621303252