没有你我就活不下去,那么,你便是我的依赖。 说白了便是:
不是我自身的,却是我须要的,都是我所依赖的。统统须要外部供应的,都是须要进行依赖注入的。
依赖注入举例
class Boy { protected $girl; public function __construct(Girl $girl) { $this->girl = $girl; }} class Girl { ...} $boy = new Boy(); // Error; Boy must have girlfriend!// 以是,必须要给他一个女朋友才行$girl = new Girl(); $boy = new Boy($girl); // Right! So Happy!
从上述代码我们可以看到Boy强依赖Girl必须在布局时注入Girl的实例才行。
那么为什么要有依赖注入这个观点,依赖注入到底办理了什么问题?
我们将上述代码改动一下我们初学时都写过的代码:
class Boy { protected $girl; public function __construct() { $this->girl = new Girl(); }}
这种办法与前面的办法有什么不同呢?
我们会创造Boy的女朋友被我们硬编码到Boy的身体里去了。。。 每次Boy重生自己想换个类型的女朋友都要把自己扒光才行。
某天Boy特殊喜好一个LoliGirl ,非常想让她做自己的女朋友。。。怎么办? 重生自己。。。扒开自己。。。把Girl扔了。。。把 LoliGirl塞进去。。。
class LoliGirl { }class Boy { protected $girl; public function __construct() { // $this->girl = new Girl(); // sorry... $this->girl = new LoliGirl(); }}
某天 Boy迷恋上了御姐....Boy 好烦。。。
是不是觉得不太好?每次碰着至心相待的人却要这么的折磨自己。。。
Boy说,我要变的强大一点。我不想被改来改去的!
好吧,我们让Boy强大一点:
interface Girl { // Boy need knows that I have some abilities.} class LoliGril implement Girl { // I will implement Girl's abilities.} class Vixen implement Girl { // Vixen definitely is a girl, do not doubt it.} class Boy { protected $girl; public function __construct(Girl $girl) { $this->girl = $girl; }} $loliGirl = new LoliGirl();$vixen = new Vixen(); $boy = new Boy($loliGirl);$boy = new Boy($vixen);
Boy 很高兴,终于可以不用扒开自己就可以体验不同的人生了。。。So Happy!
依赖注入办法
1、布局器 注入
<?phpclass Book { private $db_conn; public function __construct($db_conn) { $this->db_conn = $db_conn; }}
2、setter 注入
<?phpclass Book { private $db; private $file; function setdb($db) { $this->db = $db; } function setfile($file) { $this->file = $file; }} class file {} class db {} // ... class test { $book = new Book(); $book->setdb(new db()); $book->setfile(new file());}
小结:
由于大多数运用程序都是由两个或者更多的类通过彼此互助来实现业务逻辑,这使得每个工具都须要获取与其互助的工具(也便是它所依赖的工具)的引用。如果这个获取过程要靠自身实现,那么将导致代码高度耦合并且难以掩护和调试。
以是才有了依赖注入的观点,依赖注入办理了以下问题:
依赖之间的解耦单元测试,方便Mock上面俩种方法代码很清晰,但是当我们须要注入很多个依赖时,意味着又要增加很多行,会比较难以管理。
比较好的办理办法是 建立一个class作为所有依赖关系的container,在这个class中可以存放、创建、获取、查找须要的依赖关系。先来理解一下IOC的观点
掌握反转 (Inversion Of Control, IOC)
掌握反转 是面向工具编程中的一种设计原则,可以用来减低打算机代码之间的耦合度。个中最常见的办法叫做 依赖注入(Dependency Injection, DI), 还有一种叫\"大众依赖查找\"大众(Dependency Lookup)。通过掌握反转,工具在被创建的时候,由一个调控系统内所有工具的外界实体,将其所依赖的工具的引用通报给它。也可以说,依赖被注入到工具中。
<?php class Ioc { protected $db_conn; public static function make_book() { $new_book = new Book(); $new_book->set_db(self::$db_conn); //... //... //其他的依赖注入 return $new_book; }}
此时,如果获取一个book实例,只须要实行$newone = Ioc::makebook();
以上是container的一个详细实例,最好还是不要把详细的某个依赖注入写成方法,采取registry注册,get获取比较好
<?php/ 掌握反转类 /class Ioc { / @var array 注册的依赖数组 / protected static $registry = array(); / 添加一个 resolve (匿名函数)到 registry 数组中 @param string $name 依赖标识 @param Closure $resolve 一个匿名函数,用来创建实例 @return void / public static function register($name, Closure $resolve) { static::$registry[$name] = $resolve; } / 返回一个实例 @param string $name 依赖的标识 @return mixed @throws \Exception / public static function resolve($name) { if (static::registered($name)) { $name = static::$registry[$name]; return $name(); } throw new \Exception(\公众Nothing registered with that name\"大众); } / 查询某个依赖实例是否存在 @param string $name @return bool / public static function registered($name) { return array_key_exists($name, static::$registry); }}
现在就可以通过如下办法来注册和注入一个
<?php
Ioc::register(\"大众book\"大众, function () { $book = new Book(); $book->setdb('db'); $book->setfile('file'); return $book;}); // 注入依赖$book = Ioc::resolve('book');
问题汇总
1、参与者都有谁?
答:一样平常有三方参与者,一个是某个工具;一个是IoC/DI的容器;另一个是某个工具的外部资源。又要名词阐明一下,某个工具指的便是任意的、普通的Java工具; IoC/DI的容器大略点说便是指用来实现IoC/DI功能的一个框架程序;工具的外部资源指的便是工具须要的,但是是从工具外部获取的,都统称资源,比如:工具须要的其它工具、或者是工具须要的文件资源等等。
2、依赖:谁依赖于谁?为什么会有依赖?
答:某个工具依赖于IoC/DI的容器。依赖是不可避免的,在一个项目中,各个类之间有各种各样的关系,不可能全部完备独立,这就形成了依赖。传统的开拓是利用其他类时直接调用,这会形成强耦合,这是要避免的。依赖注入借用容器转移了被依赖工具实现解耦。
3、注入:谁注入于谁?到底注入什么?
答:通过容器向工具注入其所须要的外部资源
4、掌握反转:谁掌握谁?掌握什么?为什么叫反转?
答:IoC/DI的容器掌握工具,紧张是掌握工具实例的创建。反转是相对付正向而言的,那么什么算是正向的呢?考虑一下常规情形下的运用程序,如果要在A里面利用C,你会怎么做呢?当然是直接去创建C的工具,也便是说,是在A类中主动去获取所须要的外部资源C,这种情形被称为正向的。那么什么是反向呢?便是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中。
5、依赖注入和掌握反转是同一观点吗?
答:从上面可以看出:依赖注入是从运用程序的角度在描述,可以把依赖注入描述完全点:运用程序依赖容器创建并注入它所须要的外部资源;而掌握反转是从容器的角度在描述,描述完全点:容器掌握运用程序,由容器反向的向运用程序注入运用程序所须要的外部资源