11779


現在C#とNinjectを使ったDIについて学習を進めております．

コンストラクタ・Setter・メソッドの引数の型にインターフェイスを使う方法（※1）と比較して，DIコンテナを使う方法（※2）が優れている点がわかりません．

[code]

        interface IPerson { string Name(); }
        class Sol : IPerson { string Name() { return "Sol"; } }
        class Ky : IPerson { string Name() { return "Ky"; } }
    
        class PersonManager
        {
            private IPerson _p;
            <Inject> public PersonManager(IPerson p) { _p = p; }
            public string SayMyName() { return _p.Name(); }
        }
    
        // ※1
        void Test1()
        {
            var sol = new PersonManager(new Sol());
            sol.SayMyName();
        }
    
        // ※2
        void Test2()
        {
            var kernel = new StandardKernel();
            kernel.Bind<IPerson>().To<Sol>();
            kernel.Bind<PersonManager>().ToSelf();
    
            var sol = kernel.Get<PersonManager>();
            sol.SayMyName();
        }
    
[/code]

以下の記事を参考にコードを書きました．  
参考：taediumの日記 Ninjectを使ってみた <http://d.hatena.ne.jp/taedium/20100307/p1>

※1，※2のどちらの場合でも`PersonManager`は`IPerson`にのみ依存し，`Test1`，`Test2`はどちらも`Sol`に依存しているので，依存関係に関しては※1，※2どちらが優れているということは無いと考えています．

※2は※1よりコードが複雑になっていますし，どういう場面でDIコンテナを使用するといいのかがわかりません．

DIコンテナを使用するとこういう場面で非常に役に立つ，という例を教えてください．  
C#以外の言語，Ninject以外のDIコンテナでも構いません．

## 以下追記 2015.06.30

皆さんありがとうございます．

特に@thubさん, @unaristさんのコメントで理解が深まりました．

端的に言えば`new Sol(new Hoge(new Foo()), MAGIC_NUMBER, new
Bar())`のように生成が複雑になった場合，DIコンテナを使ったほうが便利．ということだと理解しました．

また，DIコンテナ側の機能で，オブジェクトのスコープをSingletonやThreadLocalにできたり，Privateなフィールド，メソッドにDIできるというのは確かなメリットだと感じました．

## 追記の追記(読み飛ばして結構です) 2015.07.01

私の質問の仕方が良くなかったのですが，この質問はDI自体のメリットを聞くつもりではなく，DIのコードを自分で書く場合と，DIコンテナを使った場合の差が知りたい．という意図で質問をしたつもりでした．InterfaceによるDIは日常的に行っており，そのメリットも理解・体感しております．

DIのコードを自分で書く場合も，DIコンテナを使う場合でも，オブジェクトの生成ルールを書く際は具象クラスに依存する．DIコンテナのオブジェクト生成ルールを書く場合も，自分でFactoryメソッドを用意する場合と比較してコード量も減るようには見えない．どこにメリットがあるんだろう？という疑問からの質問でした．

みなさんのコメントのおかげでとても理解が深まりました．ありがとうございました．


CC BY-SA 3.0
2015-06-26T02:54:15.063
11750
2015-07-01T08:34:17.793
2015-07-01T08:34:17.793
9532
9532
question
c# テスト
DIコンテナを使うメリットが分からない


### DIコンテナを使わない場合

[code]

    var sol = new PersonManager(new Sol());
    
[/code]

この部分は具象クラスであるSolクラスに依存してしまいます。  
PersonManagerを使う箇所が多数ある場合、`new
Sol()`する箇所も多くなります。SolクラスをKyクラスに変更したくなった場合、修正箇所が多くなりメンテナンス性が低くなります。

また、SolクラスがAクラスに依存していて、AクラスがBクラスに依存しているといった感じで、構造を持っている場合、依存性の注入を多段階で行う必要があり、`new
Sol()`する箇所が多くなると非常に辛くなってきます。構造に変更があった場合、修正が大変です。

### DIコンテナを使うと

new
Sol()する箇所をDIコンテナにバインドする一箇所に限定することができ、メンテナンス性が高くなります。構造が複雑な場合でも、構造はバインド箇所のみに隠蔽されます。  
また、DIコンテナにオブジェクトを格納して、シングルトンパターンとして利用することもでき、メモリの効率化も行えます。

PHPとpimpleというDIコンテナの例になりますが、以下のサイトが参考になります。

参考サイト  
<https://laravel10.wordpress.com/2015/03/29/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5%E3%81%A8%E3%81%AF/>


CC BY-SA 3.0
2015-06-26T04:12:03.997
11752
2015-06-26T22:11:41.333
2015-06-26T22:11:41.333
10170
10170
11750
answer


DIコンテナを使った場合、ユニットテストが容易になります。  
依存している実装を外部から差し替えることが可能になるためです。

<http://moonstruckdrops.github.io/blog/2013/06/27/dependency-injection/>


CC BY-SA 3.0
2015-06-26T04:38:21.850
11753
2015-06-26T04:38:21.850
8239
11750
answer


DI(Dependency
Injection)一般論としては、「ソフトウェア・コンポーネント間の依存性軽減」が目的でありメリットでもあると思います。コンポーネント間の依存性が小さくなる（モジュール結合度が小さくなる）ことの副次効果として、部品単位での単体テストのやり易さや、部品の再利用性向上も挙げられます。特に、大規模ソフトウェア開発でこのようなメリットが歓迎されます。

  * [なぜDIコンテナを使うのか](http://www.atmarkit.co.jp/ait/articles/0608/10/news111.html)
  * [DIの何が嬉しいの？](http://d.hatena.ne.jp/imai78/20090310/1236688846)

一方で依存性軽減の実現には、インターフェイスのような抽象レイヤを追加する必要があり、実装面ではオーバーヘッドがあることも確かです。万能なソフトウェア設計という物は存在しませんから、対象や状況に応じて採用可否を判断すべきですね。


CC BY-SA 3.0
2015-06-26T05:22:18.697
11756
2015-06-26T05:22:18.697
49
11750
answer


歴史には沿っていないと思いますが、次のように考えてみました。

  * 巨大なプログラムがある
  * それをコンポーネントに切り分けていく。けれど替えがきかない。
  * インターフェイスを挟む。替えはきくが、内部を変更する必要がある。
  * 依存性を注入する。その代りオブジェクト生成が複雑になり、その生成ロジックが分散している。
  * **あらかじめ登録しておいた生成ルールを使い、DIコンテナにオブジェクトを生成させる**

依存性の注入までは小規模のコードでもわかりやすく、実際テストに便利だったりします。一方で、それぞれのオブジェクトへの依存が少ない、質問に例示されたようなコードでは「同じ生成ロジックが分散する」と感じにくいですし、コンテナを使うメリットは薄いかもしれません。

しかし `IPerson` や `PersonManager` を生成しなければならない個所が増えた場合はどうでしょうか。個別に new
したとして、それを変更したくなったら？単に具象クラスが違うということ以外にも、生成方法が異なることがあります。あるいは既存のインスタンスを使いたいかもしれません。

DIコンテナを使えば、「これはこうすれば生成できる」というパターンを最初に登録しておくだけで、あとはコンテナが適切に組み合わせてくれます。Aが依存するBはさらにCに依存していて・・・みたいなのも含め。

また、どのような場合でも `kernel.Get<T>()`
という一貫した手順でオブジェクトを生成できるというのは、コードの可読性にもつながるのではないでしょうか。

なお、DI は外部からオブジェクトを注入しますが、直接具象クラスに依存することを避けるだけならファクトリパターンやサービスロケータといった手法もあります。

参考

  * [Dependency Injection By Hand · ninject/Ninject Wiki](https://github.com/ninject/Ninject/wiki/Dependency-Injection-By-Hand)
  * [依存性の注入 - Wikipedia](https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5)
  * [PHPメンターズ -> DIとサービスロケータの違い](http://phpmentors.jp/post/100741112503/di-service-locator)


CC BY-SA 3.0
2015-06-26T12:20:15.457
11779
2015-06-26T12:20:15.457
8000
11750
answer


マルチプラットフォーム開発をしているとDIは便利に使えます。

Hoge.Core.Dll プラットフォームに依存しないロジックが書かれている  
Hoge.Win32.Dll プラットフォーム(この場合Windows)に依存するロジックが書かれている  
Hoge.Win32.exe プラットフォームに依存したアプリケーション(この場合はWindows)  
このほかにインターフェイスを定義したDLLなどなどがあるとします。

例えばWindowsプラットフォームに依存するクラスをHoge.Win32.Dllに作って  
そのクラスを使用するクラスをPCLなどでHoge.Core.Dllとかに作ったとき。

Hoge.Core.Dll内ではHoge.Win32.Dll内のクラスを知らないままインターフェイス経由で利用しなければなりません。  
この時にクラスの生成に困るのです。そこで  
Hoge.Win32.exeにてDIの設定をすることで、  
Hoge.Core.Dll内でWin32の具象クラスを知らなくてもインスタンス化できて利用できるのです。


CC BY-SA 3.0
2015-06-27T05:55:00.987
11793
2015-06-27T05:55:00.987
8514
11750
answer


具体的な例は他の方が回答されているとおりですが、私がDIのメリットとして理解しているのは、次の点です。

  1. オブジェクトの生成の問題とその他の問題を分ける強制力となること
  2. 1の恩恵として、狭いスコープ（インターフェイス指向）でのプログラミングが可能になること
  3. 2の恩恵として、個々のクラスをメンテナンスしやすくなること

ここで、2が重要なポイントです。

質問に書かれているコードにおいて、`Test1()`、`Test2()`はいずれも、オブジェクト生成の問題と、それ以降の処理の問題とを1つの視点から見たコードになっている、という点で全く同じです。  
示されたコードの意図をそのまま、DIを活かしたコードへ書き換えることは難しいのですが、

[code]

        kernel.Bind<IPerson>().To<Sol>();
        kernel.Bind<PersonManager>().ToSelf();
    
[/code]

この2行のあたりが、オブジェクトの生成の仕方を指示しているコードですから、通常は何らかの用意された専用の場所（[モジュール](https://github.com/ninject/Ninject/wiki/Modules-
and-the-Kernel)等）へ記述して管理します。

次に、オブジェクトの生成以外の処理は、オブジェクトの生成の仕方を気にしないというだけでなく、それが具体的にどのクラスのオブジェクトであるのかも、通常は気にしないようにプログラミングします。つまり、PersonManagerを抽象化したインターフェイスのみを使うようにします。

[code]

    void Test3(IPersonManager pm)
    {
        pm.SayMyName(); // pmがSolなのかKyなのかを気にしない
    }
    
[/code]

このように、処理の部分はIPersonManagerに定義された、限られたメソッドだけを使うコードになります。

このようなスタイルでのプログラミングは、DI（コンテナ）に頼らなくても可能ですが、DIを使う場合はある意味強制的にこのようなスタイルにせざるを得なくなるため、一定の設計改善効果があるといえます。


CC BY-SA 3.0
2015-06-30T14:36:14.037
11902
2015-06-30T14:36:14.037
5444
11750
answer