百度空间 | 百度首页 
               
 
查看文章
 
依赖注入
2007年07月26日 星期四 下午 06:40

2.3   依赖注入

在前面的叙述中,我避重就轻地绕过了一个可能出现的问题,那就是具体的策略对象究竟应该怎样建立?需知,一个外部具体对象的引入,必然会给一个模块带来与该外部模块的依赖。这样一来,封装变化所带来的丰功伟绩也许会因为这样一个瑕疵,而变得荡然无存,至少,设计上的缺陷也会令我们心有戚戚焉。

确实如此,以订单管理为例。由于用户随时都可能会改变插入订单的策略,因此对于业务层的订单领域对象而言,绝不能与具体的订单策略对象产生耦合关系。也就是说,在领域对象Order类中,不能new一个具体的订单策略对象,如下面的代码:

IOrderStrategy orderStrategy = new OrderSynchronous();

虽然在前面的实现中,我们是利用领域对象的构造函数传递IOrderStrategy接口对象。但这样的实现仅仅是将具体订单策略对象的创建推迟到了领域对象的调用者那里而已,可谓是“治标不治本”的做法。我们当然也期望能够有一种理想的状态,就是具体对象的创建永远都不要在代码中出现。事实上,模块与模块间之所以产生依赖关系,正是因为有具体对象的存在。一旦在一个模块中创建了另一个模块中的具体对象,依赖就产生了。现在,我们的目的就是要将这些依赖消除。

依赖存在于模块外部,而对象的创建又是必需的。我们需要利用相关技术将外部的依赖注入到模块中,这就是所谓的“依赖注入”(Dependency Injection)。有关“依赖注入”技术,设计大师Martin Fowler撰有专文《IoC容器和Dependency Injection模式》,对依赖注入有着很好的描述。目前,实现了依赖注入的轻量级容器已经应用在许多框架产品中,如Java平台下的Spring、PicoContainer等。在.NET平台下,也有Spring.NET等容器支持依赖注入的方式。

如果没有使用诸如Spring.NET等轻量级IoC(Inversion of Control,控制反转)容器,若要实现依赖注入,则可以利用配置文件结合反射技术来完成。例如,在领域对象Order类中,可以如此实现:

public class Order

{

     private static readonly IOrderStategy orderInsertStrategy =

         LoadInsert Strategy();

     private static IOrderStrategy LoadInsertStrategy()

     {

         //通过配置文件找到具体的订单策略对象

           string path = ConfigurationManager.AppSettings["OrderStrategyAssembly"];

           string className = ConfigurationManager.AppSettings["OrderStrategyClass"];

         //通过反射创建对象实例

        return (IOrderStrategy)Assembly.Load(path).CreateInstance(className);

     }

}

在配置文件web.config中,配置如下的节:

<add key="OrderStrategyAssembly" value="BLL"/>

<add key="OrderStrategyClass" value="BLL.OrderSynchronous"/>

这其实是一种折中的Service Locator模式。将定位并创建依赖对象的逻辑直接放到对象中,不失为一种好方法,尤其是需要依赖注入的对象不太多时。但我们也可以认为这是一种无奈的妥协办法,一旦这种依赖注入的逻辑增多,就会给开发者带来一定的麻烦。此时,也许我们需要考虑应用专门的轻量级IoC容器了。

利用抽象的方式封装变化,固然是应对需求变化的王道,但它也仅仅能解除调用者与被调用者相对的耦合关系,只要还涉及具体对象的创建,即使引入了创建型模式,例如Factory Method模式,具体的工厂对象的创建依然是必不可少的。不要小看这一点点麻烦,需知“千里之堤,溃于蚁穴”,牵一发而动全身,小麻烦可能会酿成大灾难。对于那些业已被封装变化的对象,我们还应该学会利用“依赖注入”的方式来彻底解除两者之间的耦合;至于封装变化,则是实现模块解耦的重要前提。


类别:编程思想 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu