InfoQ

新闻

微软名为Unity的依赖注入Application Block发布了

作者 Robert Bazinet 译者 张善友 发布于 2008年4月17日 下午9时5分

社区
.NET,
Architecture
主题
松散耦合,
Enterprise Application Blocks
标签
依赖注入,
微软
微软模式与实践小组发布了叫做Unity或者Unity Application Block的依赖注入容器。开发人员现在能够利用可扩展的轻量级容器创建松耦合应用。

InfoQ有机会采访了Unity项目的开发领头人Chris Tavares。

Rob Bazinet (RB): Chris介绍一下你自己和你是如何参与Unity的?

Chris Tavares (CT):我的名字叫Chris Tavares。我是微软模式与实践小组的一名高级软件开发人员。我目前正在领导Enterprise Library 4和Unity Application Block的开发。我也写了大部分的Unity的代码,所以Unity的美丽都源于我的“错误”。我已经在模式与实践小组工作超过2年时间。在来微软工作之前,我从90年代开始从事工业软件外包,盒装软件开发,甚至一些嵌入式软件开发。

RB:Unity Application Block是什么?

CT:Unity是一个依赖注入(Dependency Injection,DI)容器。DI的标准描述文章来自Martin Flower[0]【译者注:中文译文参见[4]】。作为一个快速的摘要,依赖注入容器就是一个用于构建高度松耦合的软件的工具。依赖注入容器处理相互关联对象的所有细节,因此你可以构建一个独立的组件。这对可测试性和灵活性方面有很大的影响。
例如在一个银行系统的,你可以有一个对象,管理帐户转帐。要实现这个目标,需要获得个人账户的对象,再加上安全规则及审计方面的要求。 通常的实现看起来是这样的:

 AccountTransfer 
{
TransferMoney( sourceAccountNumber, destAccountNumber, amount)
{
Account sourceAccount = AccountDatabase.GetAccount(sourceAccountNumber);
Account destAccount = AccountDatabase.GetAccount(destAccountNumber);
sourceAccount.Withdraw(amount);
destAccount.Deposit(amount);
Logger.Write(, amount, sourceAccountNumber, destAccountNumber);
}
}

可以想象,这是相当可怕的代码(例如没有事务管理),虽然其可以正常工作。 ;-) 
这是很简单的,但也是高度耦合的。全局的AccountDatabase 类调用意味着你甚至不能单独编译,更别提进行测试了。如果帐号是来自两个不同的银行会发生什么呢?同样的,全局的日志记录器意味着你必须先获得一个某个明确全局记录器类所创建日志记录器后,才能使用这个类。这一结果在当你尝试编写单元测试的时候是很痛苦的,而且从长远来看也极大地限制了灵活性。
职责分离原则要求一个类不要有多个职责。在这里,这个类违反了这一原则,不仅关心如何转移资金的细节,而且还要知道如何从数据库中获取帐号和如何写日志信息。为了恢复灵活性,这些职责需要分离到不同的对象,然后在通过传递回这个对象来使用它们,看起来像这样:

 AccountTransfer 
{
IAccountRepository accounts;
ILogger logger;

AccountTransfer(IAccountRepository accounts, ILogger logger)
{
.accounts = accounts;
.logger = logger;
}

TransferMoney( sourceAccountNumber, destAccountNumber, amount)
{
Account sourceAccount = accounts.GetAccount(sourceAccountNumber);
Account destAccount = accounts.GetAccount(destAccountNumber);
sourceAccount.Withdraw(amount);
destAccount.Deposit(amount);
logger.Write(, amount, sourceAccountNumber, destAccountNumber);
}
}

这样更加封闭。现在我们不依赖于外部的全局对象,只是通过构造函数传递对象实例。这个类现在可以被单独测试,甚至可以通过简单地传入不同的IAccountRepository实现来和不同银行进行交互。
不过,现在有了新的代价。AccountTransfer的创建者现在必须知道如何创建所依赖的对象。你使用哪个帐号数据库?那个日志记录器?如果这些都是通过配置来建立,例如现在你的代码依赖于配置并且重新设计。
这就是依赖注入容器责无旁贷的,它是一个智能的对象工厂。你告诉容器如何解决特定对象的依赖关系。例如使用Unity,你可以像这样配置容器(使用API,也可以支持外部配置文件):

IUnityContainer container =  UnityContainer(); 
container.RegisterType();
container.RegisterType();

这告诉容器”如果一个依赖于IAccountRepository实例的对象,就创建一个ContosoBankRepository实例并使用它,如果任何一个对象需要一个ILogger实例,就给它一个DatabaseLogger。”你现在可以像这样要求容器给你一个由依赖关系的实例对象:

container.Resolve(); 

Resolve方法的调用试图创建一个AccountTransfer实例。容器看到构造函数需要一个IAccountRepository和一个ILogger实例,因此它创建了那些对象(使用先前指定的特定类型)并通过构造函数传递给AccountTransfer实例。这是利用容器集中组织你的应用程序的方法。这在你的应用程序中提供了一个地方处理对象之间的挂接,并且释放了对象图上单独对象的构造。由此产生的灵活性无论是可测试性还是灵活性真的是非常值得。如果你的类的依赖关系发生改变,这并不影响对象的创建,只需要配置容器就可以。

RB:Unity是Enterprise Library的一部分还是单独发布? 从我看过的资料来看,Microsoft Dependency Injection Block是作为Enterprise Library 4.0的一部分来发布的。

CT:Unity是单独发布的。Enterprise Library 4.0是建立在Unity之上的,你可以通过Unity访问Enterprise Library的功能。
需要说明一点的是,在Enterprise Library 2和Composite UI Application Block(CAB)发布的时候,这两个下面的引擎是一个叫做ObjectBuilder的类库。ObjectBuilder是一个用来构建依赖注入容器的框架。CAB和Enterprise Library都使用ObjectBuilder,但是OB是自己独立的东西,后来被单独发布[1]。
新版本的ObjectBuilder是Unity的一部分。Enterprise Library 4还是和以前一样使用ObjectBuilder:读取配置并建立适当的Enterprise Library对象。我们也引入了一种新的方式来访问Enterprise Library的功能,直接通过容器而不是把那种机制隐藏起来。Scott Densmore的一篇博客[2]详细的描述我们正在计划的工作细节。
因此,再次重申:Unity是作为一个独立的整体。Enterprise Library使用了Unity的一部分或者是可通过Unity使用。为了节省下载的麻烦,Enterprise Library包含Unity的二进制程序集。因此如果你关心的是在Enterprise Library中使用,已经为你准备好了,不需要安装额外的东西。

RB:在什么环境下,开发人员选择使用Unity?

CT:第一个问题是你是否想使用依赖注入。如果是的话,我想Unity是一个很好的选择,但是我也建议你评估一下其他的容器。Scott Hanselman列出了一些现.NET 依赖注入容器项目[3]。

RB:Unity和其他的依赖注入容器有什么不同以及和他们相比怎么样?

CT:从模式与实践上来说,在这个问题上我要非常小心。我不想给人这样的印象——不是赞同就是反对人们使用其他的项目。我们强烈建议大家评估自己的选择,并选择满足需要的最好的容器,不管是Unity还是现有的开源项目。

RB:已经有相当多的依赖注入容器,又是什么动机使得你们团队创建了Unity?

CT:模式与实践一直围绕依赖注入提供指导有一段时间了。CAB、Mobile Client Software Factory、Smart Client Software Factory、Web Client Software Factory和Enterprise Library都以“各种”方式使用依赖注入。最后一个词“各种”是致命的。虽然每个项目都建立在ObjectBuilder之上,使用依赖注入方式都是不同和不相容地。有一个明确的,功能齐全的容器对于我们围绕依赖注入提供更好的指导和基于容器的基础架构。
还有其他的原因,我们有的客户无论什么原因,不会去接触开放源代码的软件。拥有一个由微软提供支持的容器使得他们有更大的安全感,并让他们得到好处。如果他们将来选择使用其他的容器也使他们处于有利地位。
另一个目标是提高依赖注入容器在微软内外的使用。有一个微软提供的容器有助于依赖注入在广大微软.NET社区和微软内部开发人员的使用。

RB:对于开发者和团队以最好的方式开始使用Unity有什么建议?

CT抓紧下载 ,安装它并通读文档,并从我们已经发布的简单快速指南开始。

RB:有没有Unity快速指南和最佳实践的示例代码?

CT:我们已经有一个Windows Forms应用(红绿灯模拟器)小例子,利用容器注入服务。这实在是一个小型和相当容易的例子,包括C#和VB.NET版本代码。

RB:Unity有什么计划?

CT:没有什么事一成不变的,当然我个人的目标是增加一些特性(有能力拦截方法调用是列表中最高级别的),以及获得未来的模式与实践的资产以规范基于容器的基础架构。一个更好的文件配置系统。
从长远来看,我喜欢以合理的方式找一些或者所有这些概念都转换成核心平台。

RB:Chris,谢谢你接受我们的采访和这些Unity的重要信息。

从Unity的网站上看,Unity是:

Unity Application Block (Unity)是一个轻量级的, 可扩展的依赖注入容器. 它有助于构建松耦合的应用程序和为开发者提供以下便利:

  • 简化对象的创建,特别在分层对象结构和依赖的情形下
  • 它支持需求的抽象化,这允许开发人员在运行时或在配置文件中指定依赖,简化横切关注点(crosscutting concerns)的管理
  • 它通过把组件配置推给容器来决定,增加了灵活性 
  • 服务定位能力; 这使客户端能够存储或缓存容器

开发者应看Unity介绍对Unity有个总体的了解开始学习Unity。关于Unity Application Block的更多信息可参看模式与实践网站 ,并可以从CodePlex 网站下载。读者可以到Chris的博客。Enterprise Library 4.0的依赖注入发布在InfoQ2007年12月份的文章叫做微软Enterprise Library 4.0将支持依赖注入

[0] http://martinfowler.com/articles/injection.html

[1] http://www.codeplex.com/ObjectBuilder

[2] http://blogs.msdn.com/scottdensmore/archive/2008/01/31/enterprise-library-4-now-with-more-peace-love-and-rock-n-roll.aspx

[3] http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx

[4] http://www.openbeta.cn/InversionOfControlContainersAndTheDependencyInjectionPattern.ashx

查看英文原文:Microsoft Unity Dependency Injection Application Block Released
尖括号里面的代码都不见了 发表人 avant yao 发表于 2008年11月11日 下午8时40分
  1. 返回顶部

    尖括号里面的代码都不见了

    2008年11月11日 下午8时40分 发表人 avant yao

    InfoQ中文站好些(不知是不是全部)文章用到了泛型的都有这个问题。


    IUnityContainer container = new UnityContainer(); container.RegisterType<IAccountRespository, ContosoBankRepository>();
    container.RegisterType<ILogger, DatabaseLogger>();

    container.Resolve<AccountTransfer>();

深度内容

模块化Java:声明式模块化

本文是模块化Java系列文章的第4篇,介绍的是声明式模块化。文中描述了组件如何以声明的方式来定义并组织在一起,而无需让代码依赖于OSGI API。

Ian Robinson和Jim Webber谈论基于Web的整合

本采访是在伦敦举行的QCon2009上记录的,Ian Robinson和Jim Webber探讨了如何将Web作为整合平台以及REST在理论上和实践中的好处。

项目管理修炼之道(精选版)

项目管理对于项目成败至关重要,但实践中每个项目都有自己的独特性,没有现成的解决方案可以套用。书中从应对实际风险的角度出发,讲述了从项目启动、项目规划到项目结束的整个管理流程,展示了作者的思考过程。本迷你书从原书中精选出5个章节。

那是鸟,还是飞机?不,那是超人!

在这个演讲中,Fred将会揭示敏捷的一些外在因素,并会重点关注敏捷获得成功的内在原因。从案例研究和真实的项目经验来看,Fred认为:工具、管理体系都不能让你变得敏捷。敏捷的成功,植根于士气高涨、充分授权的工作者身上,他们能够以不同以往的方式思考问题。

访谈和书摘:Eben Hewitt的新书《Java SOA Cookbook》

Java SOA Cookbook

Eben Hewitt的新书《Java SOA Cookbook》从Java实现的角度讨论了面向服务架构。Eben在书中讨论了SOA基础、工具、最佳实践和SOA治理等主题。

Mark Richard的《Java消息服务》第二版

Mark Richards的新书《Java消息服务》第二版覆盖了JMS的许多主题, 包括发布和订阅模式以及点对点模式,消息过滤和事务等。InfoQ与Mark谈论了跟他的新作。

模块化Java:动态模块化

本文是“模块化Java”系列文章的第三篇,讨论动态模块化,内容涉及如何解析bundle类、bundle如何变化、以及bundle之间如何通信。

让测试也敏捷起来

对于测试组织来说,敏捷方法带来的快速迭代却让测试本身变得困难起来:缺乏“足够详细的文档”,缺乏“仔细设计用例的时间”等等。在本演讲中,段念将与大家探讨如何在敏捷过程中进行测试。