まずは定義の確認から。
依存性注入とは、コンピュータプログラムのデザインパターンの一つで、オブジェクトなどの間に生じる依存関係をオブジェクト内のコードに直接記述せず、外部から何らかの形で与えるようにする手法。
引用: IT用語辞典
とのことですが、実際にコードで見てみると理解しやすくなります。
コード例
Laravelを例としてDIを行う/行わないのコードを見てみます。
DIを行わない場合
class UserController {
public function __construct() {
$this->userService = new UserService();
}
}newでUserServiceを生成しているため、UserControllerはUserServiceに強く依存している状態となります。
DIを行う場合
class UserController {
public function __construct(UserService $userService) {
$this->userService = $userService;
}
}UserControllerはUserServiceに依存はしていますが、生成自体は外部から行われるため、依存関係が緩やかになります。
分かりやすく言うと
依存性注入を簡単に言うと、「必要なものは自分で作らず、外から渡してもらう」という考え方です。
電池を例とすると、電池が内蔵されていて外すことのできないおもちゃは、電池に強く依存しているのでDIを行っていない状態です。
一方、電池を自分で入れ替えられるおもちゃは、電池に依存はしていますが、外部から電池を渡してもらうことで依存関係が緩やかになっているため、DIを行っている状態です。
DIのなにがいいのか
DIのメリットはいくつかあります。
- 依存関係が緩やかになるため、コードの変更に強くなる。 → 電池の話を例にすると、電池を三菱製からパナソニック製に変えたい場合でも、おもちゃ自体を変更せずに電池を入れ替えるだけで済む、といったイメージでもよさそう。
- テストが容易になる。 → 電池を入れ替えられるおもちゃであれば、テスト用に特定の電池を使いたい場合でも、おもちゃ自体を変更せずに電池を差し替えるだけで済む、といったイメージです。
まとめ
依存性注入は「依存を外部から渡す」手法であり、目的としては「変更に強いコードを書くこと」や「テストを容易にすること」にあります。
理解度チェック(AI生成)
以下の4択問題で、依存性注入の理解度をチェックしてみましょう。答えは折りたたまれているので、クリックして確認してください。
Q1. 依存性注入(DI)の考え方として正しいものはどれか?
- 必要なオブジェクトはクラスの中で自分で new して生成する
- 必要なオブジェクトは自分で生成せず、外部から渡してもらう
- クラス同士の依存関係を完全になくす
- すべての処理を1つのクラスにまとめる
答えを見る
正解: 2. 必要なオブジェクトは自分で生成せず、外部から渡してもらう DIは「必要なものは自分で作らず、外から渡してもらう」という考え方です。1はDIを行わない場合の説明です。また、DIは依存関係を完全になくすものではない点に注意しましょう。
Q2. 次のコードの状態として正しいものはどれか?
class UserController {
public function __construct() {
$this->userService = new UserService();
}
}- UserControllerはUserServiceに依存していない
- UserServiceが外部から注入されているため、依存関係が緩やかになっている
- UserController内でUserServiceを生成しているため、UserServiceに強く依存している
- UserServiceがUserControllerに強く依存している
答えを見る
正解: 3. UserController内でUserServiceを生成しているため、UserServiceに強く依存している コンストラクタ内で new UserService() しているため、UserControllerは特定のUserServiceと固く結びついた状態になっています。これはDIを行っていない例です。
Q3. DIを行った場合のUserControllerとUserServiceの関係として、記事中の説明に合うものはどれか?
- UserControllerはUserServiceに一切依存しなくなる
- UserControllerはUserServiceに依存しているが、生成は外部で行われるため依存関係が緩やかになる
- UserServiceがUserControllerを生成するようになる
- UserControllerとUserServiceが1つのクラスに統合される
答えを見る
正解: 2. UserControllerはUserServiceに依存しているが、生成は外部で行われるため依存関係が緩やかになる DIを行っても「UserServiceを使う」という依存自体は残ります。変わるのは「誰が生成するか」で、生成を外部に任せることで依存関係が緩やかになります。
Q4. 記事中の電池の例えで、DIを行っている状態にあたるものはどれか?
- 電池が内蔵されていて外せないおもちゃ
- 電池を使わずに動くおもちゃ
- 電池を自分で入れ替えられるおもちゃ
- 電池とおもちゃが一体成形されたおもちゃ
答えを見る
正解: 3. 電池を自分で入れ替えられるおもちゃ 電池を外から入れられるおもちゃは、電池には依存しているものの、外部から電池を渡してもらう形になっているためDIを行っている状態です。1と4は電池に強く依存しているDIを行っていない状態です。
Q5. DIのメリットとして、記事中で挙げられているものはどれか?
- プログラムの実行速度が必ず向上する
- コードの行数が必ず減る
- テストが容易になる
- クラス間の依存関係が完全になくなる
答えを見る
正解: 3. テストが容易になる 依存するオブジェクトを外から渡せるため、テスト時にはテスト用のオブジェクト(モックなど)に差し替えられます。記事中ではもう1つのメリットとして「コードの変更に強くなる」ことも挙げられています。