1. ホーム
  2. dependency-injection

[解決済み] DIコードではなく、IoCコンテナが必要な理由とは?[クローズド]

2022-03-16 21:04:21

質問

今まで使っていた 依存性注入 (DI)は、コンストラクタ、プロパティ、メソッドのいずれかにインジェクションを行います。 私は、これまで 制御の逆転 (IoC)コンテナです。 しかし、読めば読むほど、IoCコンテナを使うようにというコミュニティからのプレッシャーを感じるようになりました。

のような.NETコンテナで遊びました。 構造マップ , NInject , ユニティ そして ファンク . IoCコンテナが私のコードにどのような利益をもたらすのか、またどのように改善されるのか、私はまだ理解できていません。

また、職場でコンテナを使い始めるのは、多くの同僚が理解できないコードを目にすることになるので、怖くてできません。彼らの多くは、新しい技術を学ぶことに消極的かもしれません。

IoCコンテナを使う必要があることを納得させてください。 職場の開発者仲間に話すときは、これらの議論を使うつもりです。

解決方法は?

うわー、ジョエルがこれを支持するなんて信じられないよ。

var svc = new ShippingService(new ProductLocator(), 
   new PricingService(), new InventoryService(), 
   new TrackingRepository(new ConfigProvider()), 
   new Logger(new EmailLogger(new ConfigProvider())));

をこの上に置く。

var svc = IoC.Resolve<IShippingService>();

多くの人は、依存関係のチェーンが入れ子になる可能性があり、それらを手動で配線するのはすぐに扱いにくくなることに気づいていません。 ファクトリーを使ったとしても、コードの重複は割に合いません。

IoCコンテナはたしかに複雑です。 しかし、この単純なケースでは、信じられないほど簡単であることをお見せしました。


さて、これをさらに正当化しましょう。 例えば、スマートUIにバインドしたいエンティティまたはモデルオブジェクトがあるとします。 このスマートUI(ここではShindows Mormsと呼ぶことにします)は、INotifyPropertyChangedを実装して、変更追跡とUIを適宜更新できるようにしたいと考えています。

OK、そんなに難しくなさそうだ」そう思って、書き始める。

まず、これで始めてください。

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime CustomerSince { get; set; }
    public string Status { get; set; }
}

...で終わりです。 これ :

public class UglyCustomer : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            string oldValue = _firstName;
            _firstName = value;
            if(oldValue != value)
                OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            string oldValue = _lastName;
            _lastName = value;
            if(oldValue != value)
                OnPropertyChanged("LastName");
        }
    }

    private DateTime _customerSince;
    public DateTime CustomerSince
    {
        get { return _customerSince; }
        set
        {
            DateTime oldValue = _customerSince;
            _customerSince = value;
            if(oldValue != value)
                OnPropertyChanged("CustomerSince");
        }
    }

    private string _status;
    public string Status
    {
        get { return _status; }
        set
        {
            string oldValue = _status;
            _status = value;
            if(oldValue != value)
                OnPropertyChanged("Status");
        }
    }

    protected virtual void OnPropertyChanged(string property)
    {
        var propertyChanged = PropertyChanged;

        if(propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

もしあなたがそのようなコードを手で書いているのなら、私は次のように主張します。 クライアントから盗んでいる . もっといい、スマートなやり方があるはずです。

ワークスマート、ノットハードという言葉を聞いたことがありますか?

では、あなたのチームの賢い人が現れて、「もっと簡単な方法がありますよ」と言ったとしましょう。

プロパティを仮想化すれば(落ち着いてください、そんな大げさなものではありませんよ)。 織る を、自動的にそのプロパティの動作に組み込むことができます。 (これはAOPと呼ばれていますが、名前は気にしないで、それが何をしてくれるかに集中してください)

どのIoCツールを使っているかにもよりますが、次のようなことができます。

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());

パッと見は 手動で行っていたINotifyPropertyChangedのBSは全て、問題のオブジェクトの全ての仮想プロパティ・セッターで、あなたのために自動的に生成されます。

これは魔法か? はい ! もし、このコードがその役割を果たすという事実を信頼できるのであれば、プロパティラッピングのような面倒なことはすべて省略できます。 あなたには解決すべきビジネス上の問題があるのです。

その他、IoCツールでAOPを行う面白い使い方もあります。

  • 宣言的なデータベーストランザクションとネストされたデータベーストランザクション
  • 宣言型&ネスト型 作業単位
  • ロギング
  • 事前/事後条件(受託設計)