Welcome

原来你是这样的Ioc

世间万物的出现必然有原因:

早在2004年,Martin Fowler就提出了“哪些方面的控制被反转了?”这个问题。他总结出是依赖对象的获得被反转了,因为大多数应用程序都是由两个或是更多的类通过彼此的合作来实现业务逻辑,这使得每个对象都需要获取与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么这将导致代码高度耦合并且难以维护和调试。 – 维基百科

一开始我们都是写着这样子的代码

1
2
3
4
5
6
7
8
9
class People
{
private $_water;
public function setWater()
{
$this->_water = new Water;
}
}

但是我们可以发现一个很蛋疼的问题,就是,卧槽,某一天我发现人进化了,不需要喝水了,而是喝汽油了,那么怎么办,因为现在这块代码中水资源和人是耦合在一起的,哭死,到处改,蛋疼,且不方便测试。OOP的编程可是一直都是强调高内聚低耦合的惹,不能让这件事情发生 …

什么叫做依赖(什么叫做依赖注入)?

我需要一种东西,但是我没有这种东西,这个东西就是我的依赖。

举个例子:人的生存需要水资源,但是水资源我们自己本身没有多余的,所以需要从外界来获取,所以水资源就是人的 依赖

1
2
3
4
5
6
7
8
9
class People
{
private $_water;
public function drink(Water $water)
{
$this->_water = $water;
}
}

代码很容易理解,但是也不容易理解+_+。

在这块代码中我们可以看到有一个Water的对象被赋值给People的一个变量中,但是发现这个Water对象是从外界注入到类中的,而不是硬编码到People类中,这样子的做饭的好处有两个:

  • 这样子相当于把代码从硬编码从解放出来了,这个可以在业务中考虑,因为人是喝水的,但是喝的水可以是不同的品种的(可以是百岁山啊,怡宝啊等),所以如果是硬编码到代码中的话如果是需求一变,那么就需要重新修改代码了,如果是这个依赖是注入的话那么就实现了代码的解耦了
  • 还有一个好处就是方便进行测试,因为这个Water的对象是外界注入的,在测试的时候就编程可控的了

什么叫做依赖查找?

依赖查找更加主动,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态。

依赖查找和依赖注入的区别

依赖注入是一种被动的行为,而依赖查找是一种主动的行为。就像是我需要一种东西,然后别人就给我一种东西,而依赖查找更像是,我需要一种东西,然后我自己通过配置去查找一种东西。

Ioc出场

通过之前的代码,我们终于可以把依赖从宿主类中的硬编码解耦出来了,但是还是存在一个问题,那就是每次我去实例化一个类的时候还是需要自己去手动的实例化一个我想要注入的类,然后注入到宿主类中,(⊙o⊙)… 虽然解耦出来,但是用得还是很不方便啊,程序员就是为了解决问题,好吧,通过查找了一下万能的wiki相关的控制反转的概念:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。 – 维基百科

好吧,现在需要一个系统,能够帮助我们自动的注入相关的依赖还有能够进行依赖查找,现在来查看下laravel的做法

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
namespace App\Jobs;
use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling;
class PurchasePodcast implements SelfHandling
{
/**
* The mailer implementation.
*/
protected $mailer;
/**
* Create a new instance.
*
* @param Mailer $mailer
* @return void
*/
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
/**
* Purchase a podcast.
*
* @return void
*/
public function handle()
{
//
}
}

借用下laravel文档中的一段代码,现在这个类中在构造函数中是注入了Mailer对象依赖,但是现在我们不需要自己来注入,因为laravel已经帮我们做好了,如果是按照下面的代码走一遍,你会发现程序能够正常的运行

1
2
3
4
5
$reflector = new ReflectionClass('App\Jobs\PurchasePodcast');
if ($reflector->isInstantiable()) {
$user = $refector->newInstance(); //in other case you can send any arguments
}

因为在实例化类的时候,laravel通过反射获取了构造函数的相关的参数,然后通过命名空间来获取需要的相关的类或者接口,然后通过调度系统中相关的映射关系来得到正确的解析之后注入到类中,简直不能再棒了…

现在我们已经大概理解了Ioc,接下来的一些博文将会说一下如何自己实现Ioc,反正很简单…