依赖注入,没那么复杂

依赖注入


没那么复杂

很多时候我们会将问题复杂化,而问题的答案却一如既往的简单。

public class Stupid
{
    protected IService Service { get; private set; }
    public Stupid()
    {
        Service = new ConcreteServiceA();
    }
}
public class Smart
{
    protected IService Service { get; private set; }
    public Smart(IService service)
    {
        Service = service;
    }
}

上面是两段看上去极其相似的类型代码,区别在于 Service 属性的初始化。前者在创建类型实例的时候直接创建Service的实例,而后者则不同:

// 假设已经有一个 IService 的实例引用:concreteServiceA
var smart = new Smart(concreteServiceA);

这就是 依赖注入(Dependency Injection,DI)

当然,这只是依赖注入的其中一种形式,因为我们至少听说过以下三种形式的依赖注入: 构造函数注入属性注入方法注入。没错,按照前面的思路,属性注入就是给属性赋值,方法注入就是用指定的参数调用方法 —— 他们都是传递一些东西(一般是另一个对象的引用)给某个对象。

是什么在误导我们

站在过高的角度上去看问题,难免会看不透问题的本质。

我们接触 依赖注入,往往起源于某个 依赖注入框架(NInject,Autofac,Castle,Unity......)。从那时起我们开始在 依赖注入框架 划定的高度上入手 依赖注入。容器?注册?解析?......依赖注入框架为我们提供了丰富强大的功能,同时也带来了一大堆概念。然之后,我们还是没搞清楚依赖注入是什么,有什么优势,甚至开始怀疑它的可用性。

可是,整个圈子都在夸赞和使用的东西,怎么可能没有利用价值呢? —— 把 依赖注入框架 当成 依赖注入,误导我们的,不是别人,是我们自己。

控制反转

说到依赖注入,就不得不提 控制反转(Inversion of Control,IoC):它不是具体技术,而是一种设计思想

前文提到的 Stupid 类型,看上去也无伤大雅,很是美观易读。可是,IService 接口的设计初衷是什么呢? Service 属性值的创建已经由 Stupid 类型的构造器完成了,IService 接口为我们带来的 多态性 在这个类里面俨然不复存在;属性值将随着 Stupid 类型实例的消逝而被回收,也不可能再被重复利用。在设计上,我们将这种情况称为 紧耦合 —— IService 接口成了摆设,ConcreteServiceAStupid 二者已是密不可分的存在。

显然,这是不合理的,我们需要改变 —— 将 Service 属性值的创建和生命周期管理交由 Stupid 类以外的地方去控制,就像 Smart 类型那样。

对的,这就是 控制反转。跟依赖注入一样,没那么复杂。

控制反转(IoC) VS 依赖注入(DI)

事实上这两者并没有什么可比性。记住一句话即可:控制反转 是一种设计思想,而 依赖注入 是 控制反转 的实现方式之一。没错,之一,因为 IoC 的实现方式不只是 DI。

posted @ 2017-05-17 00:02  饶春江  阅读(1052)  评论(2编辑  收藏  举报