为什么我需要一个IoC容器而不是简单的DI代码?
我一直在使用依赖注入(DI)一段时间,在构造函数,属性或方法中注入。 我从来没有觉得需要使用控制反转(IoC)容器。 然而,我读得越多,我感受到社区使用IoC容器的压力越大。
我使用了.NET容器,如StructureMap,NInject,Unity和Funq。 我仍然无法看到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。
“好吧,听起来不那么难”,所以你开始写作。
你从这开始:
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都将自动为您在所讨论对象的每个虚拟属性设置器上自动生成。
这是神奇吗? 是 ! 如果你可以相信这个代码完成它的工作,那么你可以安全地跳过所有包装mumbo-jumbo的属性。 你有业务问题需要解决。
IoC工具的一些其他有趣用途可用于执行AOP:
我和你在一起,瓦迪姆。 IoC容器采用了一个简单,优雅和有用的概念,并使它成为必须用200页的手册学习两天的东西。
我个人对于IoC社区如何看待Martin Fowler的一篇精美优雅的文章感到困惑不解,并将其转变为一系列通常具有200-300页手册的复杂框架。
我尽量不做评判(哈哈!),但我认为使用IoC容器的人是(A)非常聪明,(B)对那些不像他们那样聪明的人缺乏同情心。 一切都对他们很有意义,所以他们很难理解许多普通程序员会发现这些概念混淆。 这是知识的诅咒。 了解IoC容器的人很难相信有人不理解它。
使用IoC容器最有价值的好处是您可以在一个地方配置一个配置开关,让您在测试模式和生产模式之间切换。 例如,假设您有两个版本的数据库访问类...一个版本积极记录并进行了大量验证,您在开发过程中使用了这些验证,另一个版本没有日志记录或验证,而且生产速度极快。 能够在一个地方切换它们是很好的。 另一方面,这是一个相当简单的问题,不需要IoC容器的复杂性就能以简单的方式处理。
我相信,如果你使用IoC容器,坦率地说,你的代码变得难以阅读。 你必须查看哪些地方来弄清楚代码要做什么,至少增加一个。 在天堂的某个地方,一位天使在哭泣。
想必没有人强迫你使用DI容器框架。 您已经在使用DI来分离您的课程并提高可测试性,因此您可以获得很多好处。 总之,你赞成简单,这通常是一件好事。
如果您的系统达到手动DI变得繁琐(即增加维护)的复杂程度,请根据DI容器框架的团队学习曲线权衡这一点。
如果您需要更多地控制依赖项生命周期管理(也就是说,如果您觉得需要实现Singleton模式),请查看DI容器。
如果您使用DI容器,请仅使用您需要的功能。 跳过XML配置文件并在代码中进行配置(如果足够的话)。 坚持构造器注入。 Unity或StructureMap的基础可以精简为几页。
Mark Seemann在此发表了一篇很棒的博客文章:何时使用DI容器
链接地址: http://www.djcxy.com/p/14419.html上一篇: Why do I need an IoC container as opposed to straightforward DI code?