依存性注入
依存する相手を自分で作らず、外から受け取る。
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.