3

私は過去数日間、かなりの数のIOC / DI / ninjectチュートリアルとビデオを見てきましたが、それでも私が要点を理解しているとは確信していません。

ほとんどの例では、彼らは通常、次のようなことを言います。剣や手裏剣が必要な場合はどうなるか、IWeaponを定義する必要があります。実際の武器の知識を戦士から切り離したいと思います。

したがって、必要なIWeaponをWarriorに注入し、Ninject(またはその他)に必要なクラスをIWeapon(剣や手裏剣など)に入れるようにさせますが、次に、デフォルトのバインディングを作成して、 IWeaponへの剣。

どちらを使用するかをどのように判断しますか?武器に名前付きバインディングを設定してからGetを設定できないため、名前付きバインディングを使用することはできません。

私の場合、キューから読んでいるメッセージがあります。これには、何を送信し、誰に送信するかについての必要な詳細が含まれます。

SMS、電子メール、iPhoneなどの実装でメッセージを送信する方法を知っているインターフェイスもあります。この場合、コードのどこかにスイッチを配置しないと、DIの使用方法を理解できません:-(

public interface INotify
{
    void Send(Message msg);
}

public class Message
{
    public Message(INotify notify)
    {
        _notify = notify;
    }
    public void Send()
    {
        _notify.Send(this);
    }

    readonly INotify _notify;
    public string Type { get; set; }
    public string Text{ get; set; }
    public string Name { get; set; }
    public string Number { get; set; }
    public string Email { get; set; }
}


_kernel.Bind<INotify>().To<NotifyEmail>();
//kernel.Bind<INotify>().To<NotifySMS>().Named("sms");
//kernel.Bind<INotify>().To<NotifyAPNS>().Named("iphone");

var msg = _kernel.Get<Message>();
msg.Send();

必要なクラスを簡単にインスタンス化できるようにすることが重要ではありませんか?

4

4 に答える 4

4

DIの主な利点は、保守性です。コード内の統一された場所に構成されているように、DIに依存関係を注入させることにより、プログラムの進化に合わせてさまざまなクラスを簡単に入れ替えることができます。これらの依存関係は通常インターフェースに基づいているため、これにより緩い結合が強制されます。あなたが武器で述べたように、アイデアはあなたの異なるコンポーネントが正しく機能するためにお互いについて「知る」必要がないということです。

DIの最大の利点は、テストに関してです。DIは通常、明示的なクラスではなくインターフェイスによって依存関係を定義することを意味するため、プログラムの特定の側面をテストしようとしているときに、これらの依存関係を簡単にスタブ化できます。

これが役立つ場合の良い例は、プログラムがプロキシクラスを介してWebサービスにアクセスしている場合です。これは、アプリケーションのテスト中に呼び出すのが合理的でない場合があります。を介してWSにアクセスする代わりに、MyProxyDIを使用してを介してWSにアクセスすることができますIMyProxy。次に、ダミー値を返すスタブプロキシを作成し、Webサービス自体に直接アクセスせずにアプリケーション内の他のコンポーネントをテストできるようにします。

とはいえ、私の個人的な経験では、DIはすべてのシナリオの特効薬ではありません。DIは、抽象化レイヤーと引き換えに複雑さのレイヤーを追加します。これは、アプリケーションのアーキテクチャの堅牢性に大きなメリットをもたらす可能性がありますが、不要な場合もあります。SOに関するこの記事依存性注入とは何ですか?DIの有用性について少し議論しています。この回答https://stackoverflow.com/a/140655/1068266私はかなり合理的な観点からDIを要約すると思います。

要するに、私はDIのためにDIを実装することを信じていません。上記の投稿で参照されているこの記事http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.htmlをお読みください。それは私が見つけた主題の最も明確で最も単純な定義です。その記事で説明されていることに基づいたパターンから利益を得ることができないと思われる場合、DIはおそらくアプリケーションの不必要な複雑さの層になります。

于 2012-12-20T07:49:20.633 に答える
4

DIは、ソフトウェアをまとめることであり、ビジネスロジックを解決することではありません。あなたのシナリオでは、悪い習慣と見なされているIoCコンテナからDTOを解決しようとします。

これは、アプリケーションを別の方法でモデル化する必要があることを意味します。たとえば、次の擬似コードは、このシナリオを処理する1つの方法のアイデアを提供します。

public interface INotify
{
    string Type { get; }
    void Send(Message msg);
}

public class Message
{
    public string Type { get; set; }
    public string Text{ get; set; }
    public string Name { get; set; }
    public string Number { get; set; }
    public string Email { get; set; }
}

public class MessageProcessor
{
    public MessageProcessor(IEnumerable<INotify> notifiers, IMessageQueue) 
    {
        this.notifiers = notifiers.ToDictionary(n => n.Type, n);  
    }

    public void Process()
    {
        while (!TerminateApplication) 
        {
            var msg = this.queue.GetNextMessage();
            this.notifiers[msg.Type].Send(msg);
        }
    }
}


public void Main() 
{
    using (var kernel = new StandardKernel())
    {
        kernel.Bind<INotifier>().To<NotifyEmail>();
        kernel.Bind<INotifier>().To<NotifySms>();
        kernel.Bind<INotifier>().To<Notify>();
        kernel.Bind<MessageProcessor>().ToSelf();

        kernel.Get<MessageProcessor>().Process();
    }
}    
于 2012-12-20T09:26:18.913 に答える
3

一般に、依存性注入とは、依存性を自分で解決する必要があるクラスを解決することであり、代わりに、それらの作業を行うためにいくつかの高レベルのコードに依存させることです。

依存性注入の利点は、保守性の向上、単一責任による単純さであり、テスト時にモック依存性を注入できるため、単体テストの重要なイネーブラーです。

Ninjectや他の同様のIOCコンテナーのようなフレームワークは、一般に、特定の解決策が依存関係のすべてのインスタンスに適用される、アプリケーション全体のレベルで存在する依存関係を管理する便利な方法を提供します。

一方、メッセージの例は、各解決策がいくつかの条件に依存しているシナリオ主導の状況を扱っています。

シナリオ主導の状況で依存性注入を使用することは依然として有用であり、依存性注入の場合でもすべての利点が得られます。しかし、あなたが述べたように、正しい解像度を提供するには、switchまたはif/else構造を使用する必要があります。これらの条件付き構造は、依存関係を持つクラスを調整する、より高いレベルの制御コードに存在する必要があります

于 2012-12-20T07:47:10.817 に答える
2

名前付きバインディングを使用する代わりに、コンテキストバインディングを使用できます。構成を書き直して、注入のターゲットに応じて正確に注入するものを自動的に検出します。

kernel.Bind<INotify>().To<NotifyEmail>();
kernel.Bind<INotify>().To<NotifySms>().WhenInjectedInto<SmsService>();
kernel.Bind<INotify>().To<NotifyAPNS>().WhenInjectedInto<IPhoneService>();

しかし、私が理解している限り、これはあなたの問題を部分的に解決します。

メッセージキューを処理するには、依存性注入ではなく、ファクトリのようなものが必要だと私には思えます。例えば:

var factory = new Dictionary<string, Func<Message>>
{
    { "unknow", () => new Message(new NotifyEmail()) },
    { "sms", () => new Message(new NotifySms()) },
    { "iphone", () => new Message(new NotifyAPNS()) }
};

factory["iphone"]().Send();

場合によっては、複雑な実装を構築する必要がある場合は、依存性注入とを使用した抽象ファクトリINotifyの両方の利点があります。この場合、新しいファクトリインターフェイスを定義し、それがどのように動作するかを定義できます。ninject.extensions.factory

kernel.Bind<INotify>().To<NotifyEmail>()
        .NamedLikeFactoryMethod<INotify, INotifocationFactory>(f => f.GetNotifyEmail());
kernel.Bind<INotify>().To<NotifySms>()
        .NamedLikeFactoryMethod<INotify, INotifocationFactory>(f => f.GetNotifyEmail());
kernel.Bind<INotify>().To<NotifyAPNS>()
        .NamedLikeFactoryMethod<INotify, INotifocationFactory>(f => f.GetNotifyEmail());

// receive INotifocationFactory using constructor injection,
// do not resolve it directly, because this will led you to ServiceLocator anti-pattern
var abstractFactory = kernel.Get<INotifocationFactory>();

var factory = new Dictionary<string, Func<Message>>
{
    { "unknow", () => new Message(abstractFactory.GetNotifyEmail()) },
    { "sms", () => new Message(abstractFactory.GetNotifyEmail()) },
    { "iphone", () => new Message(abstractFactory.GetNotifyAPNS()) }
};

factory["iphone"]().Send();

kernel.Bind<INotifocationFactory>().ToFactory();

最後のサンプルは非常に複雑で、5セントの概念の25ドルの用語である可能性があります。したがって、特定の場合にどのソリューションを使用するかはすべてあなた次第です

于 2012-12-20T09:06:02.043 に答える