38088


<https://github.com/Swinject/Swinject>

一般的なDIコンテナの話がしたいのですが、何か具体的な例があったほうがよいと思い、上記のDIコンテナを例に書きます。

READMEにある通り、下記で `I'm playing with Mimi.` と出力できます。

[code]

    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."
    
[/code]

上記は

[code]

    let person = PetOwner(pet: Cat(name: "Mimi"))
    person.play()
    
[/code]

と同じことをやっているに過ぎません。（[やはりあなた方のDependency Injectionはまちがっている。](http://blog.a-way-
out.net/blog/2015/08/31/your-dependency-injection-is-wrong-as-I-
expected/)によるとこれで立派な`DIパターン`となります。）

さて、では別の`PetOwner`のインスタンスと別の`Cat`のインスタンスを紐付けるにはどうすればよいのでしょうか？

やりたいコード例としては下記です（下記をDIコンテナでやるにはどうするのか？）。  
そもそも一般的なDIコンテナはこのような使用は想定されていないのでしょうか？？

[code]

    let owner1 = PetOwner(pet: Cat(name: "Mimi"))
    let owner2 = PetOwner(pet: Cat(name: "Kiki"))
    
    owner1.play()
    owner2.play()
    
[/code]


CC BY-SA 3.0
2017-09-21T02:44:30.860
38080
2019-06-29T09:13:38.180
2019-06-29T09:13:38.180
9008
9008
question
swift swinject dependency-injection
一般的にDIコンテナは複数インスタンスには使用しない？


( swift は分からず、私の知識ベースは Java での DI コンテナーですが。。 )

私の知る限りでは、 DI はデータやエンティティ的なオブジェクトを取り扱うのには向いていないと思います。

というのも、 DI 利点は、あっちこっちで同じオブジェクト (以下 Dependency Object) を用いるオブジェクトたちを、 同じ
Dependency Object でもって初期化してまわるコード (ファクトリ)
を記述するのがとてつもなく手間なので、これを簡略化するために行われるものだからです。主にサービス層のオブジェクト群がこれの恩恵を受けられます。

で、どのように簡略化するかというと、

  * オブジェクトに一意の名前を付けて、その名前を指定するだけで、 Dependency Object をフィールドに注入してくれるようにする。もしクラスに対してインスタンスが一意ならば、それを自動的に引っ張ってくる。

が DI の本質です。

ここでのトレードオフはどうなっているかというと

  * すべての Dependency オブジェクトに一意の名前を付与して管理する手間  
(クラスに対してオブジェクトが一意であるならば、これをクラス名で自動的に解決できる)  
＋ DI コンテナの管理の手間

  * vs
  * すべての Dependency オブジェクトを DI 対象オブジェクトに手動でセットするコードを記述する手間

です。

データ的なオブジェクトは、それをフィールドにセットしておきたいオブジェクトをつくるさいには、素直に手動でセッターでセット、ないしコンストラクターに与える方が、コンテナという「ID
->
インスタンス解決機構」に自分で生成のたびに登録して、インスタンスが必要なくなったらコンテナから削除して、、をどうのこうのするよりずっと楽になると思います。


CC BY-SA 3.0
2017-09-21T06:13:12.083
38088
2017-09-21T06:13:12.083
754
38080
answer