依存性注入

依存性注入

執筆済 ソフトウェア開発設計

依存する相手を自分で作らず、外から受け取る。

swift
// 注入しない — 自分で作る
final class Service {
    private let api = APIClient()      // 差し替えられない
}

// 注入する
final class Service {
    private let api: APIClientProtocol
    init(api: APIClientProtocol) { self.api = api }
}

何が変わるか#

効果 内容
テストできる モックを渡せる
依存が見える イニシャライザを見れば分かる
差し替えられる 環境ごとに実装を変える
結合が下がる 具体的な型を知らなくてよい

2 つ目が特に大きい。 中で APIClient() を作っていると、 そのクラスが何に依存しているかがコードを読まないと分からない

注入の方法#

方法 特徴
イニシャライザ注入 依存が明示され、不変にできる。既定
プロパティ注入 循環がある場合。可変になる
メソッド注入 その呼び出しだけで必要な場合
Environment SwiftUI の階層を通した注入

DI コンテナ#

依存関係を登録しておき、自動で組み立てる仕組み。

利点 欠点
組み立てのコードが減る 依存が実行時にしか分からない
設定を一元化できる 追いにくい、初期化順序の問題

小〜中規模ならコンテナは不要。 イニシャライザで手で渡すのが単純で確実。 Swift のように型が強い言語では、 コンパイル時に検査される方が価値が高い。

Service Locator との違い#

DI            : 必要なものを外から渡される(依存が見える)
Service Locator: 必要なときに取りに行く(依存が隠れる)

Service Locator は Singleton と同じ問題を持つ。 依存が隠れるので、テストと理解が難しくなる。

参考文献#

  • Martin Fowler. Inversion of Control Containers and the Dependency Injection pattern. 2004. https://martinfowler.com/articles/injection.html
  • Robert C. Martin. Clean Architecture: A Craftsman’s Guide to Software Structure and Design. Prentice Hall, 2017.
  • Martin Fowler. Patterns of Enterprise Application Architecture. Addison-Wesley, 2002.
ノート一覧を閉じる