首页 > 代码库 > 软件开发--依赖注入

软件开发--依赖注入

控制反转(Inversion of Control,缩写为IoC),是面向对象编程的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做 依赖注入(Dependency Injection,简称DI). 还有一种方式叫做 "依赖查找" (Dependency Lookup). 通过控制反转,对象

在被创建时,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中.

Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。

采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。

依赖注入有如下实现方式:
基于接口。实现特定接口以供外部容器注入所依赖类型的对象。
基于 set 方法。实现特定属性的public set方法,来让外部容器调用传入所依赖类型的对象。
基於构造函数。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。

 

1. 依赖

如果在 Class A 中,有 Class B 的实例,则称 Class A 对 Class B 有一个依赖。例如下面类 Human 中用到一个 Father 对象,我们就说类 Human 对类 Father 有一个依赖。

public class Human {
...
Father father;
...
public Human() {
father = new Father();
}
}

仔细看这段代码我们会发现存在一些问题:
(1). 如果现在要改变 father 生成方式,如需要用 new Father(String name) 初始化 father,需要修改 Human 代码;
(2). 如果想测试不同 Father 对象对 Human 的影响很困难,因为 father 的初始化被写死在了 Human 的构造函数中;
(3). 如果 new Father() 过程非常缓慢,单测时我们希望用已经初始化好的 father 对象 Mock 掉这个过程也很困难。

2. 依赖注入

上面将依赖在构造函数中直接初始化是一种 Hard init 方式,弊端在于两个类不够独立,不方便测试。我们还有另外一种 Init 方式,如下:

public class Human {
...
Father father;
...
public Human(Father father) {
this.father = father;
}
}

上面代码中,我们将 father 对象作为构造函数的一个参数传入。在调用 Human 的构造方法之前外部就已经初始化好了 Father 对象。像这种非自己主动初始化依赖,而通过外部来传入依赖的方式,我们就称为依赖注入。
现在我们发现上面 1 中存在的两个问题都很好解决了,简单的说依赖注入主要有两个好处:
(1). 解耦,将依赖之间解耦。
(2). 因为已经解耦,所以方便做单元测试,尤其是 Mock 测试。

 

软件开发--依赖注入