DIコンテナがあるのに依存を外から注入する必要はあるのか?
参考ソース
https://github.com/Swinject/Swinject
のREADMEに下記のソースがあります。
(ライブラリにかかわらず、DIコンテナ特有の問題として語れると考えています)
protocol Animal {
var name: String? { get }
}
class Cat: Animal {
let name: String?
init(name: String?) {
self.name = name
}
}
protocol Person {
func play()
}
class PetOwner: Person {
let pet: Animal
init(pet: Animal) {
self.pet = pet
}
func play() {
let name = pet.name ?? "someone"
print("I'm playing with \(name).")
}
}
let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") }
container.register(Person.self) { r in
PetOwner(pet: r.resolve(Animal.self)!)
}
let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with Mimi."
PetOwnerは引数にAnimalをもらっているがもらう必要があるのだろうか??
PetOwner
はイニシャライザでAnimal
をもらっています。
そのため PetOwner(pet: r.resolve(Animal.self)!)
と外側から注入しています。
これは冗長に感じます(確かにDIは外から注入するものなのかもしれないですが...)。
以下のように書き換えて内部で注入してしまえばいいように感じます。
テストで注入するデータを入れ替えたいのであれば、テスト用の register
を書けば注入されるインスタンスは変わるはずです。
let container = Container() // アプリであれば、シングルトンなどとしてずっと生きているようにする
protocol Animal {
var name: String? { get }
}
class Cat: Animal {
let name: String?
init(name: String?) {
self.name = name
}
}
protocol Person {
func play()
}
class PetOwner: Person {
let pet: Animal
init() {
self.pet = container.resolve(Animal.self)! // 内部で注入
}
func play() {
let name = pet.name ?? "someone"
print("I'm playing with \(name).")
}
}
container.register(Animal.self) { _ in Cat(name: "Mimi") }
container.register(Person.self) { r in
PetOwner()
}
let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with Mimi."
質問
テストで注入するデータを入れ替えたいのであれば、テスト用の register を書けば注入されるインスタンスは変わるはずです。
コンテナから直接取り出せるのに、外側から(引数で)渡す(注入する)必要があるのでしょうか?