摘要
IoC:Inversion of Control 控制反转
DI:Dependency Injection 依赖注入
IoC与DI
先记住这句话:IoC是设计模式,而DI是IoC控制反转设计模式的典型实现
IoC控制反转是一种设计模式,用来解决对象间的过度依赖问题。
解决思路是:设法不在依赖对象中去获取(new)被依赖对象,最典型的的实现方式就是DI依赖注入了。
将对象所依赖的其他对象,在类外部生成好之后,传递到类内部的,而不是在类的内部实例化。这种解决依赖的方法就是DI依赖注入。
例如:对象Hero依赖对象Sword,我们可以选择如下定义方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 英雄依赖宝剑的定义实现 class Sword { private $title; public function __construct($title) { $this->title = $title; } } class Hero { private $weapon; public function __construct() { // Hero依赖Sword $this->weapon = new Sword('倚天剑'); } }
上面的代码中,Hero类对象就依赖Sword对象,但是在此例子中,Hero类对象对于Sword类对象的依赖就比较严重,一旦这个Hero使用的不再是Sword,而是Gun了,Hero的内部方法就要重写,在复杂的程序中,是不可取得,需要降低Hero对武器(无论是Sword或者Gun亦或者是其他武器)的直接依赖
解决思路就是设法不在依赖对象中去获取需要依赖的对象,这种思路就是IoC控制反转。
把原来本应在类(对象)内部完成的依赖,设法在类(对象)外部完成,这个由内到外的转化过程就是反转
所以:IoC反转最典型的实现方式就是依赖注入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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 /** * 武器接口 * Interface Weapon */ interface Weapon { public function __construct($title); /** * 进攻 */ public function attack(); } /** * 宝剑类 */ class Sword implements Weapon { protected $title; public function __construct($title) { $this->title = $title; } public function attack() { return "我的{$this->title}打起来唰唰唰~"; } /** * 枪类 */ class Gun implements Weapon { protected $title; public function __construct($title) { $this->title = $title; } public function attack() { return "我的{$this->title}打起来砰砰砰~"; } } class Hero { private $weapon; /** * * 构造方法的参数是一个对象,通过类型约束限制必须为实现Weapon武器接口的对象 * 在构造方法中,直接将参数传递进来的武器对象赋值到当前对象的属性上 * 这样,英雄Hero依赖的对象不是在Hero类的内部实例化,而是在外部实例化好,传递到Hero内部的 * * 这就是《依赖注入》,通俗来讲,就是所依赖的对象在外部生成好之后,传递到类内内部的,而不是在 * 类内部实例化,这种解决依赖的方法就是DI依赖注入 * * * * Hero constructor。 * * @param Weapon $weapon */ public function __construct(Weapon $weapon) { $this->weapon = $weapon; } public function myWeapon() { echo $this->weapon->attack(); }
调用测试:
1 2 3 4 5 6 7 8 //用宝剑的英雄 $class = new Hero(new Gun('倚天')); $class->myWeapon(); //我的倚天打起来唰唰唰~ //用枪的英雄 $class = new Hero(new Sword('沙漠之鹰')); $class->myWeapon(); //我的沙漠之鹰打起来砰砰砰~
这样,无论Hero需要宝剑还是枪,都可以通过外部注入的方式,将武器传递给Hero对象
通过构造方法传递参数,是依赖注入最常用的形式,除此之外,还有属性赋值的方法,也可以完成依赖注入,例如:
1 2 3 4 5 6 7 // class Hero { public $weapon; } $hero = new Hero; $hero->weapon = new Sword('倚天');
以上就是平时所说的依赖注入,有没有理解呢?
结语
解决了什么是依赖注入的问题, 本篇的目的就达到了,(示例代码在这里 ,本文参考引用这里 ) 但还远远不够 , 注意上面的使用Hero的代码, 我们是手动将实例化好的武器对象作为参数传递给Hero的构造方法的。 此时的问题就是, 当出现大量的, 随机的需要注入的依赖如何处理? 一个个的实例化传递, 是否够自动化?
要解决这个问题, 就出现了IoC容器。 IoC容器也称为服务容器。 主要就是解决依赖和注入的问题。 实现机制是通过预先将创建对象的代码绑定或注册到IoC容器中, 然后利用该IoC容器创建对象, 在创建对象的过程中, 通过分析对象所需要的依赖(一般利用反射机制), 将注册好的创建对象的代码注入到对象的构造方法中去, 从而完成自动解决这个依赖注入的问题。 非常智能。
下篇我会接着记录