3

在過去的幾天裏,我已經看了不少IOC/DI/ninject教程和視頻,但我仍然不相信我明白了。Ninject/DI在簡單場景中有用嗎?

在大多數例子,他們通常這樣說,如果我們想劍或飛鏢,我們需要定義IWeapon發生。我們想要分離戰士對實際武器的知識。因此,我們將所需的IWeapon注入戰士,然後讓Ninject(或其他)讓我們進入IWeapon(比如劍或手裏劍)所需的類,但是然後他們繼續創建一個默認綁定,創建一個默認綁定劍與武器的單一綁定。

我們如何告訴它使用哪一個?我們不能使用命名綁定,因爲你不能在武器上設置命名綁定,然後設置Get。

在我來說,我有一個消息,我從隊列中讀取,它會包括什麼派,誰發送到所需的詳細信息。

我也有一個接口,知道如何發送短信,電子郵件,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

DI是關於把你的軟件放在一起,而不是解決你的業務邏輯。在您的場景中,您嘗試從IoC容器中解析DTO's,這被認爲是不好的做法。

這意味着您必須以不同的方式建模您的應用程序。例如。下面的僞代碼將爲您提供一種處理這種情況的方法:

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(); 
    } 
}  
+0

我喜歡它,特別是IOC如何爲我提供所有通知程序的列表。當我爲Google爲什麼從國際奧委會獲得DTO時Google很糟糕,這很糟糕,我再次看到了你的名字:-) –

3

依賴注入在一般約爲開脫類爲解決他們的依賴關係爲自己,而是爲他們依靠一些更高級別的代碼來爲他們工作。

依賴注入的好處是通過單一責任來提高可維護性和簡單性,並且是單元測試的重要推動因素,因爲在測試時可以注入模擬依賴關係。

框架,如Ninject和其他類似的IOC容器通常提供管理存在在應用層面上,在那裏特定分辨率應用到依賴的每個實例依賴的便捷方式。

在另一方面,你的消息實例處理一個情景驅動的情況下,每個分辨率取決於一些條件/秒。

它仍然是使用依賴注入的情況下驅動的情況下非常有用,並且還是會給予你,如果依賴注入的所有好處。但正如你所說的,有必要使用開關或if/else結構來提供正確的分辨率。這些條件結構應該存在於某些更高級別,控制即編排有依賴

4

DI的主要優點是可維護性類代碼。通過讓DI爲您注入您的依賴關係(如代碼中的統一位置所配置的那樣),隨着程序的發展,您可以更輕鬆地交換進入和退出不同的類。由於這些依賴通常基於接口,因此會強制實現鬆耦合。正如你提到的武器,這個想法是,你的不同組件不必「知道」彼此才能正常工作。

DI最大的優勢就是測試。因爲DI通常意味着通過接口而不是顯式類來定義依賴關係,所以當您試圖測試程序的某個特定方面時,可以很容易地對這些依賴關係進行存根。

如果您的程序通過代理類訪問web服務,這在您的應用程序測試過程中調用可能不合理,一個很好的示例是哪裏有用。不要通過MyProxy訪問WS,您可以使用DI通過IMyProxy訪問WS。然後,您可以創建一個存根代理,它返回虛擬值,並允許您在應用程序中測試其他組件,而無需直接訪問webservice本身。

說了這麼多,以我個人的經驗來看,DI並不是每個場景的靈丹妙藥。 DI爲一層抽象增加了一層複雜性。這對您的應用程序體系結構的健壯性有很大的好處,但它也可能是不必要的。這篇關於SO What is dependency injection?的文章對DI的有用性進行了一些討論。這個答案https://stackoverflow.com/a/140655/1068266我想以相當合理的方式總結DI。

總之,我不相信爲了DI而實施DI。閱讀本文後面提到的http://www.jamesshore.com/Blog/Dependency-Injection-Demystified.html這篇文章。這是我找到的最清楚和最簡單的主題定義。如果您不認爲您可以從該文章中解釋的模式中受益,則DI可能會在您的應用程序中造成不必要的複雜層次。

2

而不是使用命名綁定您可以使用Contextual Binding。重寫你的配置automaticaly檢測正是注入取決於注入的目標:

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美元的任期。所以這一切都取決於你在特定情況下使用什麼解決方案

相關問題