DI

DI就是常说的依赖注入,那么究竟什么是依赖注入呢?

打个比方,电脑(非笔记本哈)需要键盘和鼠标我们才能进行操作,这个‘需要’换句话说就是‘依赖’键盘和鼠标。

那么,相应的,一个类需要另一个类才能进行作业,那么这也就是依赖。

看一段代码:

class Computer {protected $keyboard;public function __construct() {$this->$keyboard = new Keyboard();}
}这里的Computer类依赖了键盘类。

好,既然我们已经知道了什么是依赖,那么什么是注入呢?

我们改造一下上面的代码:

 class Computer {protected $keyboard;public function __construct(Keyboard $keyboard) {$this->$keyboard = $keyboard;}
}$computer = new Computer(new Keyboard());这里的Computer类依赖注入了Keyboard类。

关于依赖注入,我的理解是:

所需要的类通过参数的形式传入的就是依赖注入。

理解了依赖注入,我们可以接着理解IOC。
IOC

IOC是什么呢?

中文叫控制反转。啥意思呢? 这个看明白了DI后就能很容易的理解了。

通过DI我们可以看到,一个类所需要的依赖类是由我们主动实例化后传入类中的。

控制反转和这个有什么关系呢?

控制反转意思是说将依赖类的控制权交出去,由主动变为被动。

看一段laravel代码:

namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SessionController extends Controller
{public function login(Request $request){//这就是IOC,我们不需要主动传入类了一切由laravel去实现}
}

看到这你可能有疑问了,这是怎么实现的呢?

这就是靠服务容器了,请往下接着看。
服务容器

看了很多文章,我一致认为服务容器就是一种设计模式。

它的目的就是解耦依赖。

它有点类似于我前面说的《享元模式》。区别在于服务容器解决了所有依赖的实现。

这里我们再从头至尾的看一遍,怎么一步步演化出服务容器。

依然是电脑的例子,我们知道电脑依赖键盘鼠标,可是键盘鼠标也有很多种呀。

先看一个最原始的代码例子:

 class Computer {protected $keyboard;public function __construct($type == null) {switch($type) {case 'common':$this->keyboard = new CommonKeyboard();break;case 'awesome':$this->keyboard = new AweSomeKeyboard();break;default:$this->keyboard = new Keyboard();break;}}
}

或许你一眼就看出了问题在哪。

如果我们又要增加一钟键盘,那我们又得对这个类进行修改。这样下去,这个类会变得庞大且耦合程度过高。

那么我们可以怎么修改呢?

工厂模式

这样我们可以避免直接的修改Computer类。

    简单工厂
class Factory {public static function getInstance($type){switch($type) {case 'common':$this->keyboard = new CommonKeyboard();break;case 'awesome':$this->keyboard = new AweSomeKeyboard();break;default:$this->keyboard = new Keyboard();break;}}
}class Computer {protected $keyboard;public function __construct($type == null) {$this->keyboard = Factory::getInstance($type);}
}

这样使用简单工厂模式后,我们后续的修改可以不用对Computer类进行操作而只要修改工厂类就行了。这就相当于对Computer类进行了解耦。

Computer类虽不在依赖那些键盘类了,但是却变为依赖工厂类了。

后续添加新类型的键盘就必须对工厂类进行修改。

所以这个工厂类还不能很好的满足要求,我们知道电脑对键盘的接口都是一致的,键盘必须实现这一接口才能被电脑识别,那我们对Computer和Keyboard类进行修改。

DI(依赖注入)interface Board {public function type();
}class CommonBoard implements Board {public function type(){echo '普通键盘';}
}class MechanicalKeyboard implements Board {public function type(){echo '机械键盘';}
}class Computer {protected $keyboard;public function __construct (Board $keyboard) {$this->keyboard = $keyboard;}
}$computer = new Computer(new MechanialKeyBoard());

可是这样也有问题,如果我们后续对这台电脑使用的键盘不满意要进行替换呢? 我们又回到原点了,必须去修改传入的键盘类。

能不能做成可配置的呢?

IOC服务容器(超级工厂)
class Container
{protected $binds;protected $instances;public function bind($abstract, $concrete){if ($concrete instanceof Closure) {$this->binds[$abstract] = $concrete;} else {$this->instances[$abstract] = $concrete;}}public function make($abstract, $parameters = []){if (isset($this->instances[$abstract])) {return $this->instances[$abstract];}array_unshift($parameters, $this);return call_user_func_array($this->binds[$abstract], $parameters);}
}这就是一个简单的IOC服务容器。这个怎么解决我们上述的问题呢?$container = new Container;$container->bind('Board', function($container){return new CommonBoard;});$container->bind('Computer',function($container,$module){return new Computer($container->make($module));});$computer = $container->make('Computer',['Board']);这里生产出来的Computer类就是一个使用普通键盘的电脑类了。解释一下代码:bind(name,function($container){return new Name;})这里的name和Name之间的关系是:当我需要name类的时候你就给我实例化Name类。make(name)方法是对name进行生产返回一个实例。如果我们要更换键盘怎么办呢?$container->bind('Board', function($container){return new MechanicalBoard;});$container->bind('Computer',function($container,$module){return new Computer($container->make($module));});$computer = $container->make('Computer',['Board']);

只要对bind绑定的Board类的实现进行修改,我们就可以很容易替换掉键盘了。这就是一个服务容器。

对服务容器进行一个理解:

容器就是一个装东西的,好比碗。而服务就是这个碗要装的饭呀,菜呀,等等东西。当我们需要饭时,我们就能从这个碗里拿到。如果你想在饭里加点菜(也就是饭依赖注入了菜),我们从碗里直接拿饭就可以了,而这些依赖都由容器解决了(这也就是控制反转)。

我们需要做的就是对提供的服务进行维护。

我们看一段真实的在laravel框架上能跑的代码:
// IOC 处理依赖


class Me {protected $something;public function __construct(Something $something ) {$this->something = $something;}
}class Something {}App::bind('foo', function(){return new Me(new Something());
});dd(App::make('foo'));

当然laravel框架的服务容器比这里的要复杂很多了,但我们明白了它的使用目的以及使用场景就不难去入手laravel了。

Laravel服务容器相关推荐

  1. laravel 服务容器,容器概念

    Laravel 服务容器 发现一篇讲服务容器的文章,讲的很好,转载过来laravel 服务容器 实质是工厂模式的升级,类的传递动态加载 ####以下内容转载 容器,字面上理解就是装东西的东西.常见的变 ...

  2. laravel服务容器-----深入理解控制反转(IoC)和依赖注入(DI)

    首先大家想一想什么是容器,字面意思就是盛放东西的东西,常见的变量,对象属性都是容器,一个容器能够装什么东西,完全在于你对这个容器的定义.有的容器不仅仅只是存文本,变量,而是对象,属性,那么我们通过这种 ...

  3. php--理解PHP的依赖注入和laravel的服务容器

    写在前面 为了了解laravel的服务容器在网上搜了许多文章,其中大多数都有其侧重点,没有很系统的一套东西以供参考,看完之后仍觉似乎少了一根把他们串起来的绳子,近期有幸拜读了陈昊的<Larave ...

  4. Laravel神奇的服务容器

    Laravel的核心是IocContainer, 文档中称其为"服务容器",服务容器是一个用于管理类依赖和执行依赖注入的强大工具,Laravel中的功能模块比如 Route.Elo ...

  5. Laravel 学习笔记 —— 神奇的服务容器

    原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器 ...

  6. laravel —— 神奇的服务容器

    容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存放的不是文本.数值,而是对象.对象的描述(类.接口)或 ...

  7. php ico容器,Laravel 核心——IoC 服务容器

    服务容器 Laravel 服务容器是一个用于管理类依赖和执行依赖注入的强大工具. 在理解这句话之前,我们需要先了解一下服务容器的来龙去脉: laravel神奇的服务容器.这篇博客告诉我们,服务容器就是 ...

  8. laravel-神奇的服务容器(转)

    原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器 ...

  9. Laravel开发:Laravel核心——Ioc服务容器源码解析(服务器绑定)

    服务容器的绑定 bind 绑定 bind 绑定是服务容器最常用的绑定方式,在 上一篇文章中我们讨论过,bind 的绑定有三种: 绑定自身 绑定闭包 绑定接口 今天,我们这篇文章主要从源码上讲解 Ioc ...

最新文章

  1. Linux安装jdk学习
  2. 常用开源代码网站集合
  3. my batis plus 小数没有0_Excel中的数据去掉小数点,教你3个函数解决!
  4. php匿名类的应用场景,【modernPHP专题(9)】匿名类
  5. CISCO无线AP配置手册
  6. 为什么情人总比老婆好
  7. 1104File Space Bitmap Block损坏能修复吗
  8. Cesium:各种坐标转换
  9. 12 浏览器对象模型BOM
  10. MySQL如何使用索引 较为详细的分析和例子
  11. 蓝屏dump分析教程
  12. JAVA实现图片验证码 超详细教程
  13. Ubuntu下安装Nodejs, Nide
  14. 知识图谱嵌入|KG-BERT代码 ConvE ConvR
  15. Linux的简单命令 who echo cal clear date
  16. 微信图片翻译技术优化之路
  17. C语言—超长正整数的乘法实现简洁版
  18. GBase 8a MPP Cluster 维护-日志篇
  19. 【强烈推荐】人工智能系列文章推送公告!!!
  20. R语言小白学习笔记12—概率分布

热门文章

  1. scrapy安装_「从零开始Python爬虫」1.8.3 Scrapy-Splash的安装
  2. python精确匹配字符串_Python: 字符串搜索和匹配,re.compile() 编译正则表达式字符串,然后使用match() , findall() 或者finditer() 等方法...
  3. javascript动态字母
  4. 清除eclipse当前登录的SVN账户
  5. ehcache 实现缓存共享
  6. 谷歌Chrome浏览器开发者工具教程—JS调试篇
  7. MyBatis foreach语句批量插入数据
  8. axios请求拦截器错误_React中使用高阶组件和axios的拦截器,统一处理请求失败提示...
  9. python变量的作用_Python中的变量
  10. python中文显示不出来_Python查询数据库,中文的结果显示不出来