依赖注入和依赖注入容器概念解析

什么是依赖注入?

DI的核心是把类所依赖的单元的实例化过程,放到类的外面去实现。以降低代码耦合度
一般实现方式分为构造函数注入和属性注入

示例

传统实现方式 在类的内部对其所依赖的单元进行实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//发送消息抽象层
interface SenderInterface
{
public function send();
}

//发送消息通知类
class SendDing implements SenderInterface
{
public function send()
{
...
}
}

//业务类
class MyService
{
public function __construct()
{

}

public function doSomething()
{
...

$obj = new SendDing();
$obj->send()

}
}

$service = new MyService();
$service->doSomething();

依赖注入实现方式一(构造函数注入在类的外部对其所依赖的单元进行实例化,并通过类的构造函数注入到类的内部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

//业务类
class MyService
{
private $_sendObj;
public function __construct($sendObj)
{
$this->_sendObj = $sendObj;
}

public function doSomething()
{
...

$this->_sendObj->send()

}
}

$sendObj = new SendDing();
$service = new MyService($sendObj);
$service->doSomething();

依赖注入实现方式二(属性注入在类的外部对其所依赖的单元进行实例化,并通过类的属性注入到类的内部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

//业务类
class MyService
{
public $_sendObj;
public function __construct()
{

}

public function doSomething()
{
...

$this->_sendObj->send()

}
}

$sendObj = new SendDing();
$service = new MyService();
$service->_sendObj = $sendObj;
$service->doSomething();

从以上示例中可以看出,传统的实现方式,在类的内部实例化了其所依赖的发送钉钉消息的类。
假如某一天我们不想发钉钉了,改发短信了,那么我们必须修改业务类中 new SendDing()语句,
但是依赖注入方式,就实现了MyService类和SendDing类之间的解耦,无论以后发钉钉、发短信
还是发邮件,只有实现了SenderInterface的send方法,我们的业务类就不需要做任何变动,
提高了代码的复用性

依赖注入容器

依赖注入容器负责对对象及对象的所有依赖,和这些依赖的依赖,进行实例化和配置。

可以想像,一个Web应用的某一组件会依赖于若干单元,这些单元又有可能依赖于更低层级的单元, 从而形成依赖嵌套的情形。
那么,这些依赖单元的实例化、注入过程的代码可能会比较长,前后关系也需要特别地注意, 必须将被依赖的放在需要注入依赖
的前面进行实例化。为了解决这一问题,就设计出了DI容器。

DI容器的实例示例,直接看下节对Yii依赖注入容器实现的解析