DI(Dependency Injection)の概要


#この記事は何か
　少し前に話題になったクリーンアーキテクチャーの中で出てきたDI(Dependency Injection: 依存性の注入)について、自分なりに解釈したものです。
#DIとは
　あるオブジェクトと別のオブジェクトの間の依存関係を薄くするために、依存関係を外から注入するという考え方です。
　まず、依存性の高いプログラムの例を紹介します。

```Swift
class User {
    let firstName = "Taro"
    let familyName = "Yamada"

    func fullname() -> String {
        return firstName + " " + familyName
    }
}

class Presenter {
    let user = User()   // (1)

    func present() {
        print(user.fullname())
    }
}

let presenter = Presenter()
presenter.present()
```
　このような例の場合、`Presenter`クラスは、`User`クラスを内部で作成、所持しています(1)。`Presenter`のインスタンスは、`User`のインスタンスがなければ存在もできません。`User`クラスへの依存性が非常に高い、ということです。
　ここで、依存性を低くしてみます。

```Swift
class User {
    (上の例と同じ)
}

class Presenter {
    var user: User!   // (2)

    func present() {
        print(user.fullname())
    }
}

let presenter = Presenter()
let user = User()
presenter.user = user   // (3)
presenter.present()    
```
　`Presenter`クラス内部で`User`クラスを作ることはなくなり(2)、外部で作ったuserを注入しています(3)。字面どおりの「依存性の注入」です。userには、Userクラスを継承したクラスのインスタンスを指定できるので、自由度も増しました。しかし、(2)で `var user: User!`を指定している以上、内容的に`User`に依存していることには変わりありません。
　そこで、次の例です。

```Swift
protocol UserSpec {   // (4)
    func fullname() -> String
}

class User: UserSpec {   // (5)
    let firstName = "Taro"
    let familyName = "Yamada"

    func fullname() -> String {
        return firstName + " " + familyName
    }
}

class Presenter {
    var user: UserSpec!   // (6)

    func present() {
        print(user.fullname())
    }
}

let Presenter = Presenter()
let user = User()
presenter.user = user
presenter.present()
```
　`UserSpec`というプロトコルが登場しました。そして、`User`は`UserSpec`に適合し(5)、`Presenter`は`User`の代わりに`UserSpec`に適合したインスタンスを所有します。これにより、`user`は、`User`を継承したクラスではなく、`UserSpec`に適合したクラスのインスタンスを使用することができます。
# DIの勘所
　上の例では、「`User`クラスの`fullname()`メソッドを取り出して、`UserSpec`プロトコルにまとめただけ」にしか見えません。しかし、ここでは、発想を逆にしてみます。つまり、
**`Presenter`は設計図である`UserSpec`を作った。下請けである`User`は、その設計図に合わせた実装を作った。**
という発想です。こうすることで、`Presenter`と`User`の間に主従関係が見えてきます。
　今回は、既存のクラスをDI対応にするため、下請けクラスの関数をプロトコルとして取り出しましたが、今後新しくクラスを作るときは、下請けが適合すべきプロトコルを先に作り、下請けクラスがそれを実装する、という流れを作ればいいのです。
# クリーンアーキテクチャーへの適用
　最初に出てきた[クリーンアーキテクチャー](http://blog.tai2.net/the_clean_architecture.html)は、外側の円は内側の円のことを知っているが、内側の円は外側を知らない、というのが原則です。ですから、内側の円が外側にアクセスしたい時に、DIを使って「下請けに出す」を実装すれば良いわけです。
　上の例では、画面に文字を表示する`Presenter`がデータを保持する`User`を下請けにしていましたが、クリーンアーキテクチャー的には主従関係が逆になります。そこで、このように変更しました。

```Swift
protocol PresenterSpec {
    func nameChanged()
}

class User {
    var presenter: PresenterSpec!

    var firstName = "Taro" {
        didSet {
            presenter.nameChanged()
        }
    }
    var familyName = "Yamada" {
        didSet {
            presenter.nameChanged()
        }
    }
    func fullname() -> String {
        return firstName + " " + familyName
    }
}

class Presenter: PresenterSpec {

    func nameChanged() {
        print(user.fullname())
    }
}

let presenter = Presenter()
let user = User()
user.presenter = presenter
user.familyName = "Kawada"
```
　若干恣意的ではありますが、`PresenterSpec`に定義している関数は、名前が変わったことを通知する`nameChanged()`関数であり、`PresenterSpec`に適合したクラスがどんな処理をするのか`User`クラスは知りません(`firstName`だけ表示する処理かもしれませんし、ひょっとしたら、表示をせずにデータベースに保存するという処理かもしれません)。
　これで、`User`は外側の円のことを一切知ることなく、`firstName`または`familyName`が変更されたことだけを通知し、`Presenter`が`fullname`を表示するようになります。
　さらに、中から外、外から中の両方のアクセスにDIを使っても良いでしょう。

```Swift
protocol PresenterSpec: class {
    func nameChanged()
}

class User: UserSpec {
    weak var presenter: PresenterSpec!

    var firstName = "Taro" {
        didSet {
            presenter.nameChanged()
        }
    }
    var familyName = "Yamada" {
        didSet {
            presenter.nameChanged()
        }
    }
    func fullname() -> String {
        return firstName + " " + familyName
    }
}

protocol UserSpec {
    func fullname() -> String
}

class Presenter: PresenterSpec {
    var user: UserSpec!

    func nameChanged() {
        print(user.fullname())
    }
}

let presenter = Presenter()
let user = User()
user.presenter = presenter
presenter.user = user
user.familyName = "Kawada"

```
　こうすると、主従関係がわかりにくい気がしますが、「データの管理は`User`が主、表示に関しては`Presenter`が主」と考えれば良いと思います。
# ファイルの構成
　実際のプログラミングでは、すべてのクラスやプロトコルを一つのファイルに収めることはしないので、先ほどの例をファイル単位に分割します。`User.swift`はこうなりました。

```Swift
protocol PresenterSpec: class {
    func nameChanged()
}

class User {
    weak var presenter: PresenterSpec!

    var firstName = "Taro" {
        didSet {
            presenter.nameChanged()
        }
    }
    var familyName = "Yamada" {
        didSet {
            presenter.nameChanged()
        }
    }
}

extension User: UserSpec {

    func fullname() -> String {
        return firstName + " " + familyName
    }

}
```
　`User.swift`ファイルには、`User`クラス本体と、`User`が欲している`PresenterSpec`プロトコル、そして、`Presenter`クラスから要求されている`UserSpec`プロトコルの実装を記載します。`UserSpec`プロトコルは`Presenter`が必要としているものであるので、プロトコルの定義そのものを`User`クラスと同じファイルには記載しません。
　ファイルサイズが大きくなるにつれ、この3つのブロックも別々のファイルに書くことになるかと思いますが、`User`クラスと`UserSpec`プロトコルの定義は別々であるべき、ということは間違いないでしょう。
# 余禄
　ここで挙げた例は、DIの説明といいつつも、実はプロトコルの説明にすぎません。DIが役に立つのは、ユニットテストの時だけだ、という人もいるそうです。どういった時にDIが役に立つのか、もう少し勉強したいと思います。
　そう言えば、現在iOS, macOSで使用しているCocoaフレームワークはObjective-C時代に作られたものであり、随所にSwiftの考え方とそぐわない部分があります。Swiftのバージョンアップに伴い少しずつ改変が入っていますが、SwiftのABIの安定化が図られたら、次は、Cocoaフレームワークの大規模な改変が始まる、という可能性もあるかもしれません。クリーンアーキテクチャーなどを使って、できるだけフレームワークへの依存度を減らしておくと良いかもしれませんね。