版权属于:
桑帅东的博客
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
概念
依赖注入一词是由 Martin Fowler 提出的术语,它是将组件注入到应用程序中的一种行为。就像 Ward Cunningham 说的:
依赖注入是敏捷架构中关键元素。
什么是依赖
打个比方,就好比每个人都需要穿衣服才能进行正常的社会活动,这就是说是个人都需要依赖衣服才能正常社会活动。
相应的,就是一个类需要另一个类才能完成工作,这就是依赖
下面是person类依赖了衣服类
class Person{
protected $clothes;
public function __construct()
{
$this->clothes = new Clothes();
}
}
看上面的代码就知道 人依赖了衣服,
什么是依赖注入呢,我们改造下上面的代码
class Person {
protected $clothes;
public function __construct(Clothes $clothes) {
$this->clothes = $clothes;
}
}
$person = new Person(new Clothes());
这里的Person 依赖注入了clothes类
什么是控制反转(IOC)
结论就是,造车难,买车容易,在写程序的时候使用依赖注入可以更好的解耦
先看自己造车代码
<?php
class Car
{
//汽车可以跑,定义一个方法 run()
public function run(){
return '滴滴滴,车开了';
}
}
class Person
{
private $car = null;//保存某人的车,暂时还没车
public function drive(){
$this->car = new Car();//要开车先造车,造了一辆车保存在某人的 $car 里
return $this->car->run();//调用车的 run() 方法
}
}
$xiaoming = new Person();
echo $xiaoming->drive();//输出 滴滴滴,车开了
通过经销商依赖注入
<?php
class Car
{
//汽车可以跑,定义一个方法 run()
public function run()
{
return '滴滴滴,车开了';
}
}
class Person
{
private $car = null;//保存某人的车,暂时还没车
//new 某人的时候,就给他注入一辆车,通过 $a 传入构造方法,并保存在 $car 里
public function __construct($a)
{
$this->car = $a;
}
public function drive()
{
return $this->car->run();//调用车的 run() 方法
}
}
$car = new Car();//买一辆车
$xiaoming = new Person($car);//new 小明的时候,把刚才买的车注入
echo $xiaoming->drive();//输出 滴滴滴,车开了
万一 new 小明的时候,给他买了一架飞机,并注入,小明不会开飞机怎么办,通过类型限定解决这个问题
class Person
{
.
.
.
public function __construct(Car $a)// <----这里做类型限定,保证不会注入飞机,也不会注入火箭
{
$this->car = $a;
}
.
.
.
IOC容器
在上例中,我们是手动的去 new 一辆车并注入给某人,现在用一个容器统一的去管理这些需要注入的类。
<?php
class Car
{
//汽车可以跑,定义一个方法 run()
public function run()
{
return '滴滴滴,车开了';
}
}
class Person
{
private $car = null;//保存某人的车,暂时还没车
//new 某人的时候,就给他注入一辆车,通过 $a 传入构造方法
public function __construct(Car $a)// <----这里做了类型限定
{
$this->car = $a;
}
public function drive()
{
return $this->car->run();//调用车的 run() 方法
}
}
//写一个简单的 IoC 容器类
class Container{
private static $objArr = [];//定义一个静态的空数组
public static function set($flag, Callable $func){
self::$objArr[$flag] = $func;//存入键值对,键是一个字符串,作为标识符,值是一个匿名函数
}
public static function get($flag){
$tmp = self::$objArr[$flag];//取出标识符对应的匿名函数,用$tmp临时保存一下
return $tmp();//在$tmp后名加上括号,表示执行这个函数,并返回
}
}
//下面这条语句执行完毕后,会在 $objArr 里存入一个键值对,键是 car ,值是这个匿名函数,该匿名函数返回的是创建 Car 对象的语句
Container::set('Car', function(){
return new Car();
});
//下面这条语句执行完毕后,会在 $objArr 里存入一个键值对,键是 person ,值是这个匿名函数,该匿名函数返回的是创建 Person 对象的语句
Container::set('Person', function(){
return new Person(Container::get('Car'));//直接去容器中取一辆车出来,并作为参数传给 Person 类的构造函数
});
$xiaomin = Container::get('Person');//直接去容器中取一个人出来,取名叫小明
echo $xiaomin->drive();//输出 滴滴滴,车开了
IOC 是什么呢,看明白了依赖注入 (DI) 后就很容易理解了
通过 DI 我们可以看到,一个类所需要的依赖类是由我们主动实例化后传入类中的。
控制反转的意思就是说将依赖类的控制权交出去,由主动变被动。
Setter 方法注入#
class UserProvider{
protected $connection;
public function __construct(){
...
}
public function setConnection( Connection $con ){
$this->connection = $con;
}
...
接口注入#
interface ConnectionInjector{
public function injectConnection( Connection $con );
}
class UserProvider implements ConnectionInjector{
protected $connection;
public function __construct(){
...
}
public function injectConnection( Connection $con ){
$this->connection = $con;
}
}
所以,简单讲只要不是由内部生产(比如初始化、构造函数 __construct 中通过工厂方法、自行手动 new 的),而是由外部以参数或其他形式注入的,都属于依赖注入(DI) 。是不是豁然开朗?事实上,就是这么简单。
评论