代码改变世界

抓虫系列(五) 浅谈依赖注入与控制反转

2011-10-23 23:09  熬夜的虫子  阅读(3379)  评论(1编辑  收藏  举报

前篇回顾:前篇虫子介绍了3个"池"中线程池的相关问题,不过谬论的可能性比较大 仅代表虫子的个人观点了 - -

本章结合实例给大家阐述下依赖注入与控制反转可以给自己的项目带来哪些优缺点。

先回顾下OO的一些设计原则:

开放封闭原则  软件实体(类、模块、函数等)应该是可以开展的,但是不可修改。

依赖倒置原则 抽象不应该依赖于细节。细节应该依赖于抽象。

接口隔离原则 不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。

单一职责原则 就一个类而言,应该仅有一个引起它变化的原因。

......

随着面向对象分析与设计的发展,一个良好的设计,核心原则之一就是将变化隔离,使得变化部分发生变化时,不变部分不受影响(这也是OCP的目的)。为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖于一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。
但是,客户类在运作中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。
依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中, 客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。
OK,概念性的东西已经占了不少篇幅了,下面虫子结合一个低侵入性、通过配置文件实现注入的实例 来看看实际的效果如何。

 BaseClass.cs中提供基本的功能类和接口定义

public interface IocObj
{
      TestObj GetTestObj(string QQName);
}
public class TestObj
{
      public string QQ { get; set; }
}

 Content01.cs中实现一种功能

 public class Con1 : IocObj
    {
        public TestObj GetTestObj(string QQName)
        {
            return new TestObj { QQ = QQName+" 这是con1" };
        }
    }

  Content02.cs中实现另一种功能

public class Con2 : IocObj
    {
        public TestObj GetTestObj(string QQName)
        {
            return new TestObj { QQ = QQName + " 这是con2" };
        }
    }

下面我们就看看如何进行依赖注入,关于分析xml以及反射等细节处理本篇先暂不介绍,主要介绍下依赖注入带来的影响与效果

控制台程序

static void Main(string[] args)
        {
            var IOCService = ServiceLocator.GetService<IocObj>();
            var TestObj = IOCService.GetTestObj("1326194996");
            Console.WriteLine("当前用户的qq为" + TestObj.QQ);
            Console.ReadLine();
        }

配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="ChongZi" type="ChongZi.Config.ConfigSectionHandler, ChongZi.IOC" />
  </configSections>
  <ChongZi>
    <objects>     
      <add name="Content01" type="BaseClass.IocObj, BaseClass" mapTo="Content01.Con1, Content01" />
    </objects>
  </ChongZi>
</configuration>

看结果

 修改下配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="ChongZi" type="ChongZi.Config.ConfigSectionHandler, ChongZi.IOC" />
  </configSections>
  <ChongZi>
    <objects>      
      <add name="UserServiceLocal" type="BaseClass.IocObj, BaseClass" mapTo="Content02.Con2, Content02" />
    </objects>
  </ChongZi>
</configuration>

再看结果

结果一目了然,实例也很简单。但是依赖注入给项目带来的意义还是很大的。而且通过一些RMI组件我们还可以注入远程对象、服务。对于分布式开发也提供了积极的解决方案。不过既然是抓虫系列,当然也要谈谈这种模式的缺点,首先对象生成的步骤变复杂,其次,涉及反射对性能上也是个损耗。至于大家的项目中是否需要依赖注入和控制反转,取决于项目对可维护性以及可扩展性的需求。