【Xcode/Swift】Dependency Injectionを活用する

DI (Dependency Injection) を学ぶ機会があったので備忘録として記事を書こうと思いました

Dependency Injectionとは?

*直訳

【Dependency Injection】= 依存性注入

Dependency injection means giving an object its instance variables. Really. That's it.
(依存性注入とは、オブジェクトをインスタンス変数(定数)に渡すこと、ただそれだけです) *海外サイトより

文字通り依存性を注入する、という意味合いですがこれだけではイメージし辛いと思うのでサンプルコードを書いて具体例を見てみましょう。


Dependency Injectionを活用した機能

RegisterRepositoryProtocol というプロトコルに準拠したRegisterRepository というクラスをそれぞれ【本番用】【テスト用】に分けて作ってみます。

import Foundation

// MARK: - Protocol
protocol RegisterRepositoryProtocol { // プロトコルを作成
    func register()
}

// MARK: - Production
class RegisterRepository: RegisterRepositoryProtocol { // プロトコルに準拠したクラスを作成 (本番用)
    func register() {
        print("Production Register")
    }
}

// MARK: - Test
class TestRegisterRepository: RegisterRepositoryProtocol { // プロトコルに準拠したクラスを作成 (テスト用)
    func register() {
        print("Test Register")
    }
}

// MARK: - UserRegister
class UserRegister {
    private let repository: RegisterRepositoryProtocol
    init(repository: RegisterRepositoryProtocol) {
        self.repository = repository
    }
    func register() {
        repository.register()
    }
}

冒頭で書いた、【インスタンス変数(定数)に渡す】ということは以下のような意味合いです。

import UIKit

class ViewController: UIViewController {

//    private let repository = RegisterRepository() // インスタンス化 (本番)
    private let testRepository = TestRegisterRepository() // インスタンス化 (テスト)

    override func viewDidLoad() {
        super.viewDidLoad()
        dependencyInjection()
    }

    private func dependencyInjection() {
        // Initializeするときに準拠したクラスを注入させる
        let userRegister = UserRegister(repository: testRepository)
        userRegister.register()
    }

}

このような記述にすることで、本番用クラスとテストクラスをインスタンスする箇所で切り替えるだけなのでテストがしやすくなります。

この場合のDIは 【コンストラクタインジェクション】と呼ばれ、Initializeするときにインスタンスを注入します。

【セッターインジェクション】という形式もあり、Initializeした後に注入するやり方ですがこの場合は注入忘れが起こる場合があるので基本的には【コンストラクタインジェクション】を採用すれば良さそうです。


まとめるほどでもない

インプットしただけでは分からない概念や実装方法は実際にサンプルコードを書いて感覚的に覚える方が身につきやすいですね