Swinjectのコンテナ階層について動作確認した

結論からいうと動いた。

$ swift -F . -target x86_64-apple-macosx10.12 main.swift
With parent container: Meow
With child container: Bow wow

みんな大好きDIコンテナ、その中でもあるといいなと思う機能の一つはモジュールの一部のみの差し替えですよね。 SwiftのDIコンテナであるSwinjectでもコンテナ階層( https://github.com/Swinject/Swinject/blob/master/Documentation/ContainerHierarchy.md )という文書化されていたので出来るかなと思い試してみました。

モジュールの一部のみ差し替えができると何がうれしいのか。 典型的なケースでは、ビジネスロジックが共通で使う外部サービスへのアダプタをDIするとき、ある特定のケースのみ特殊なアダプタに差し替えたい、という要求をDIの枠組みのなかだけで表現できるようになります。

以下、コードです。

import Swinject

protocol Animal {
    func sound() -> String
}

class Cat: Animal {
    func sound() -> String {
        return "Meow"
    }
}

class Dog: Animal {
    func sound() -> String {
        return "Bow wow"
    }
}

protocol Person {
    var pet: Animal { get }
}

class PetOwner: Person {
    let pet: Animal

    init(pet: Animal) {
        self.pet = pet
    }
}

let parent = Container()
parent.register(Animal.self) { _ in Cat() }
parent.register(Person.self) { r in
    PetOwner(pet: r.resolve(Animal.self)!)
}

let child = Container(parent: parent)
child.register(Animal.self) { _ in Dog() }

var person = parent.resolve(Person.self)!
print("With parent container:", person.pet.sound())

person = child.resolve(Person.self)!
print("With child container:", person.pet.sound())