话说 依赖注入(DI) or 控制反转(IoC)
科普:
首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程序间的耦合,鄙人学习了一下,看TP官网还没有相关的文章,就写下这篇拙作介绍一下这种设计模式,希望能为TP社区贡献一些力量。
首先先别追究这个设计模式的定义,否则你一定会被说的云里雾里,笔者就是深受其害,百度了N多文章,都是从理论角度来描述,充斥着大量的生涩词汇,要么就是java代码描述的,也生涩。
不管怎么样,总算弄清楚一些了,下面就以php的角度来描述一下依赖注入这个概念。
先假设我们这里有一个类,类里面需要用到数据库连接,按照最最原始的办法,我们可能是这样写这个类的:
- class example {
- private $_db;
- function __construct(){
- include "./Lib/Db.php";
- $this->_db = new Db("localhost","root","123456","test");
- }
- function getList(){
- $this->_db->query("......");//这里具体sql语句就省略不写了
- }
- }
过程:
在构造函数里先将数据库类文件include进来;
然后又通过new Db并传入数据库连接信息实例化db类;
之后getList方法就可以通过$this->_db来调用数据库类,实现数据库操作。
看上去我们实现了想要的功能,但是这是一个噩梦的开始,以后example1,example2,example3....越来越多的类需要用到db组件,如果都这么写的话,万一有一天数据库密码改了或者db类发生变化了,岂不是要回头修改所有类文件?
ok,为了解决这个问题,工厂模式出现了,我们创建了一个Factory方法,并通过Factory::getDb()方法来获得db组件的实例:
- class Factory {
- public static function getDb(){
- include "./Lib/Db.php";
- return new Db("localhost","root","123456","test");
- }
- }
sample类变成:
- class example {
- private $_db;
- function __construct(){
- $this->_db = Factory::getDb();
- }
- function getList(){
- $this->_db->query("......");//这里具体sql语句就省略不写了
- }
- }
这样就完美了吗?再次想想一下以后example1,example2,example3....所有的类,你都需要在构造函数里通过Factory::getDb();获的一个Db实例,实际上你由原来的直接与Db类的耦合变为了和Factory工厂类的耦合,工厂类只是帮你把数据库连接信息给包装起来了,虽然当数据库信息发生变化时只要修改Factory::getDb()方法就可以了,但是突然有一天工厂方法需要改名,或者getDb方法需要改名,你又怎么办?当然这种需求其实还是很操蛋的,但有时候确实存在这种情况,一种解决方式是:
我们不从example类内部实例化Db组件,我们依靠从外部的注入,什么意思呢?看下面的例子:
- class example {
- private $_db;
- function getList(){
- $this->_db->query("......");//这里具体sql语句就省略不写了
- }
- //从外部注入db连接
- function setDb($connection){
- $this->_db = $connection;
- }
- }
- //调用
- $example = new example();
- $example->setDb(Factory::getDb());//注入db连接
- $example->getList();
这样一来,example类完全与外部类解除耦合了,你可以看到Db类里面已经没有工厂方法或Db类的身影了。我们通过从外部调用example类的setDb方法,将连接实例直接注入进去。这样example完全不用关心db连接怎么生成的了。
这就叫依赖注入,实现不是在代码内部创建依赖关系,而是让其作为一个参数传递,这使得我们的程序更容易维护,降低程序代码的耦合度,实现一种松耦合。
这还没完,我们再假设example类里面除了db还要用到其他外部类,我们通过:
- $example->setDb(Factory::getDb());//注入db连接
- $example->setFile(Factory::getFile());//注入文件处理类
- $example->setImage(Factory::getImage());//注入Image处理类
- ...
我们没完没了的写这么多set?累不累?
ok,为了不用每次写这么多行代码,我们又去弄了一个工厂方法:
- class Factory {
- public static function getExample(){
- $example = new example();
- $example->setDb(Factory::getDb());//注入db连接
- $example->setFile(Factory::getFile());//注入文件处理类
- $example->setImage(Factory::getImage());//注入Image处理类
- return $expample;
- }
- }
实例化example时变为:
- $example=Factory::getExample();
- $example->getList();
似乎完美了,但是怎么感觉又回到了上面第一次用工厂方法时的场景?这确实不是一个好的解决方案,所以又提出了一个概念:容器,又叫做IoC容器、DI容器。
我们本来是通过setXXX方法注入各种类,代码很长,方法很多,虽然可以通过一个工厂方法包装,但是还不是那么爽,好吧,我们不用setXXX方法了,这样也就不用工厂方法二次包装了,那么我们还怎么实现依赖注入呢?
这里我们引入一个约定:在example类的构造函数里传入一个名为Di $di的参数,如下:
- class example {
- private $_di;
- function __construct(Di &$di){
- $this->_di = $di;
- }
- //通过di容器获取db实例
- function getList(){
- $this->_di->get('db')->query("......");//这里具体sql语句就省略不写了
- }
- }
- $di = new Di();
- $di->set("db",function(){
- return new Db("localhost","root","root","test");
- });
- $example = new example($di);
- $example->getList();
Di就是IoC容器,所谓容器就是存放我们可能会用到的各种类的实例,我们通过$di->set()设置一个名为db的实例,因为是通过回调函数的方式传入的,所以set的时候并不会立即实例化db类,而是当$di->get('db')的时候才会实例化,同样,在设计di类的时候还可以融入单例模式。
这样我们只要在全局范围内申明一个Di类,将所有需要注入的类放到容器里,然后将容器作为构造函数的参数传入到example,即可在example类里面从容器中获取实例。当然也不一定是构造函数,你也可以用一个 setDi(Di $di)的方法来传入Di容器,总之约定是你制定的,你自己清楚就行。
这样一来依赖注入以及关键的容器概念已经介绍完毕,剩下的就是在实际中使用并理解它吧!
本文如有错误,请务必指出,大家共同学习,共同进步。
转载请注明出处。
http://www.thinkphp.cn/topic/12180.html
话说 依赖注入(DI) or 控制反转(IoC)的更多相关文章
- 依赖注入(DI)和控制反转(IOC)
依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...
- PHP依赖注入(DI)和控制反转(IoC)详解
这篇文章主要介绍了PHP依赖注入(DI)和控制反转(IoC)的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程 ...
- 依赖注入(DI)和控制反转(IOC)的理解,写的太好了。
学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...
- 【串线篇】依赖注入DI与控制反转IOC
DI&IOC 在spring框架中DI与IOC说的其实是一回事 一句话:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象. 也就是说我对对象的『依赖』是注入进来的,而和 ...
- 轻松理解 Java开发中的依赖注入(DI)和控制反转(IOC)
前言 关于这个话题, 网上有很多文章,这里, 我希望通过最简单的话语与大家分享. 依赖注入和控制反转两个概念让很多初学这迷惑, 觉得玄之又玄,高深莫测. 这里想先说明两点: 依赖注入和控制反转不是高级 ...
- ASP.NET MVC进阶之路:深入理解依赖注入(DI)和控制反转(IOC)
0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点.在程序运行过程中,客户 ...
- PHP 依赖注入(DI) 和 控制反转(IoC)
要想理解 PHP 依赖注入 和 控制反转 两个概念,就必须搞清楚如下的两个问题: DI —— Dependency Injection 依赖注入 IoC —— Inversion of Control ...
- 聊一聊PHP的依赖注入(DI) 和 控制反转(IoC)
简介 IoC Inversion of Control 控制反转DI Dependency Injection 依赖注入 依赖注入和控制反转说的实际上是同一种东西,它们是一种设计模式,这种设计模式用来 ...
- 依赖注入(DI)与控制反转(IOC)
DI(依赖注入,Dependency Injection),和所谓的IoC(控制反转,Inversion of Control )是一个意思. DI是一种通过接口实现松耦合的设计模式.初学者可能会好奇 ...
随机推荐
- html5文章 -- HTML5开发实例-网易微博手机Web App开发过程
HTML5在国内外越来越受到互联网开发团队的青睐.国外,谷歌兴致勃勃地开发Chrome Web Store,微软发布了支持使用HTML5技术开发的“Irish Spring”主题网站,诺基亚斥巨资购得 ...
- 星外虚拟主机跨web目录文件读取漏洞
星外虚拟主机跨目录读取文件漏洞,需要一定条件. 问题发生在以下文件,这些文件都没有严格的设置执行权限,当前的IIS用户能够顺利的利用它们执行命令: c:\windows\7i24IISLOG.exe ...
- php如何判断远程文件是否存在
<?php /* 函数:remote_file_exists 功能:判断远程文件是否存在 参数: $url_file -远程文件URL 返回:存在返回true,不存在或者其他原因 ...
- php 的curl 模拟登陆
做一个类似这样的web 应用. 1,解决掉验证码 其实这是正方的一个小bug,当我们进入登陆界面时,浏览器会去请求服务器,服务器会生成一个验证码图片.如果我们不去请求这个图片,那么正方后台也不会生成相 ...
- NOJ 1641 错误的算法(模拟)
[1641] 错误的算法 时间限制: 5000 ms 内存限制: 65535 K 问题描述 有道题目是这样的: 输入一个 n 行 m 列网格,找一个格子,使得它所在的行和列中所有格子的数之和最大.如果 ...
- Gao Big 深圳行
day 1 来到深圳的国际化大都市之后,首先要做的事情就是···坐地铁?? 到了旅店,已经比较晚了,又折腾了两三下.. day 2 第二天一早,一行人出发来到深圳大学(nv shen su she)参 ...
- 一些站点使用的服务器软件、js 框架大收集 [ 整理中 ]
Chrome 的扩展应用 ChromeSnifferPlus ( 开源中国地址:http://www.oschina.net/p/chromesnifferplus,GitHub 地址:https:/ ...
- 龙珠 超宇宙 [Dragon Ball Xenoverse]
保持了动画气氛实现的新时代的龙珠视觉 今年迎来了[龙珠]系列的30周年,为了把他的魅力最大限度的发挥出来的本作的概念,用最新的技术作出了[2015年版的崭新的龙珠视觉] 在沿袭了一直以来优秀的动画世界 ...
- Ubuntu 14.04 LTS 安装 VNC Viewer
1.修改镜像源: /etc/apt/sources.list将"http://archive.ubuntu.com/ubuntu/"替换为: http://cn.archive.u ...
- 让你的PHP更安全之PHP.ini
让你的PHP更安全之PHP.ini 发布时间:2013-05-02 12:43:06 来源:PHP100论坛 评论:0 点击: 次 [字号:大 中 小] QQ空间新浪微博腾讯微博人人网豆瓣网百 ...