前言:设计模式其实是一个很空洞的东西,设计模式有几十种,有些人觉得工厂模式也单例模式已经足够解决大部分问题。而有些人觉得任何设计模式都会让开发变得更“复杂”,更“低效”。所以千万不要太过追求他的实际意义和作用,否则你已经坠入云雾。但是不管怎么样,实际工作中还是要对它们有所了解,下面从php的角度来讲一下依赖注入、控制反转、反射等概念。如有错误之处,还望路过大神多加指点

首先设定场景,假如一个类需要数据库连接,最简单的做法可能是:

    class example {private $_db; function __construct(){ include "./Lib/Db.php"; $this->_db = new Db("localhost","root","123456","test"); } function getList(){ $this->_db->query("......"); } } 

但事实上稍微有点经验的同学都不会这样写,因为一旦越来越多的类用到db,而db一旦发生变化,那么岂不是要每个文件都修改一遍?这就是程序设计中的耦合问题。所有的类过度依赖 "./Lib/Db.php" 这个文件。OK,为了解决这个问题,工厂模式出现了,我们新建一个 Factory 工厂类:

    class Factory {public static function getDb(){ include "./Lib/Db.php"; return new Db("localhost","root","123456","test"); } } class example { private $_db; function __construct(){ $this->_db = Factory::getDb(); } function getList(){ $this->_db->query("......"); } } 

如果我们用到db模块那么直接 Factory::getDb() 从工厂中取出来就是了,看似解决了问题。但事实是这样吗?不,这样只不过是把程序与 db 模块的耦合转移到了 Factory ,一旦后期业务发生变动,Factory 发生变动,依旧要对每个文件改动。那如何解决呢?

我们可以不从example类内部获取db组件,我们从外部把db组件注入进example类

    class example {private $_db; function getList(){ $this->_db->query("......");//执行查询 } //从外部注入db连接 function setDb($connection){ $this->_db = $connection; } } $example = new example(); $example->setDb(Factory::getDb());//注入db连接 $example->getList(); 

这样一来example就不用关心db组件怎么来的了,只用暴露一个注入方法即可。这就是DI/依赖注入(Dependency Injection),不在内部处理依赖关系,而是把依赖作为参数传递进去,以降低程序的耦合性。

然后我们的项目继续进行,用到了文件处理类,图像处理类,我们可能会这样写

$example->setDb(Factory::getDb());//注入db连接
$example->setFile(Factory::getFile());//注入文件处理类
$example->setImage(Factory::getImage());//注入Image处理类 

但是这样似乎也不行啊,每次都要写这么多代码,于是我们又写了一个工厂方法

    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也不直接new 了。我们用 Factory::getExample()中获取。但是,这是不是又有点熟悉的感觉?和上面第一次用工厂类的时候一样依赖于工厂。于是又有了容器的概念。

class example {private $_di; function __construct(Di &$di){ $this->_di = $di; } //通过di容器获取db实例 function getList(){ $this->_di->get('db')->query("......"); } } $di = new Di(); $di->set("db",function(){ return new Db("localhost","root","root","test"); }); $example = new example($di); $example->getList(); 

Di就是一个存放各种可扩展的组件的容器,需要注入的时候调用$di->set()方法注入组件即可。程序中即可通过$di->get() 获取组件。这样被调用的组件(db)并不是由调用者(example)创建,而是由Di容器创建,调用者失去控制权,而容器得到控制权,发生了控制权转移,所以叫做控制反转(Inversion of Control)

但是这样又有一些比较有强迫症的同学发现了,每个类都要注入一遍容器是不是有些麻烦。没错,其实注入容器这个动作可以交给另外的程序处理,那就是反射。

<?php
/**
* example
*/
class example { //通过di容器获取db实例 function getList(){ $this->_di->get('db')->query("......"); } } //di容器 class Di{ public $_container; public function get($cls){ return $this->_container[$cls]; } public function set($cls,$_instance){ $this->_container[$cls]=$_instance; } } //db组件 class db{ private static $_instance;//保存单例 //单例方法 public static function getInstance(){ if(!(self::$_instance instanceof self)){ self::$_instance = new self; } return self::$_instance; } //查询方法 public function query($sql){ echo $sql; } } $di = new Di();//实例化容器 $di->set('db',db::getInstance()); //注入db实例 $reflector = new ReflectionClass('example'); //反射example,通过反射可以获得该类的所有信息 $reflector->getDefaultProperties(); //example属性 $reflector->getDocComment(); //注释 $instance =$reflector->newInstanceArgs(); //相当于实例化反射的example类 $instance->_di=$di; //注入di容器 $reflector->getmethod('getList')->invoke($instance);//调用example类方法 

通过反射我们可以得到该类的全部信息,包括方法、方法名、属性甚至注释等等。通过反射我们可以方便的控制程序中使用的类,对他们进行扩展、修正、以及监听。通常反射在插件开发和框架开发中大量应用。在框架开发中也会把反射与依赖注入、控制反转搭配使用,让程序有强大的可控性和扩展性。

eg:反射主要是用在“单一出口”的情况下使用,比如mvc框架,基本上都是由框架核心类解析url,得到指向的文件名类名方法名,然后加载对应的控制器文件,然后用反射注入容器就可以了,并不需要每次都写。

转载于:https://www.cnblogs.com/yhdsir/p/5751173.html

浅谈依赖注入与控制反转相关推荐

  1. 依赖注入框架Dagger2详解(一),依赖注入和控制反转的深入理解

    IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合.更优良的程序,而Dagger2框架是依赖注入思想践行者的优秀代表. 依赖注入框架Dagger2详解(一), ...

  2. [翻译]StructureMap 指南 – .NET中的依赖注入和控制反转

    原文地址:http://www.pnpguidance.net/Post/StructureMapTutorialDependencyInjectionIoCNET.aspx StuctureMap ...

  3. springboot的IOC依赖注入与控制反转-举例(转载+自己整理)

    这个记录是对[1]的整理和简化,便于日后遗忘时迅速恢复记忆. Spring框架有四大原则: ①使用POJO进行轻量级与最小侵入式开发 ②通过依赖注入和基于接口编程实现松耦合 ③通过AOP和默认习惯进行 ...

  4. Spring依赖注入和控制反转

    文章目录 1.依赖注入 1.1.依赖注入和控制反转的概念 1.2.依赖注入的实现方式 1.3.控制反转的具体实现 1.4.依赖注入的具体实现 1.5.依赖注入和控制反转总结 1.依赖注入 1.1.依赖 ...

  5. 简单解释什么是 依赖注入 和 控制反转

    简单解释什么是 依赖注入 和 控制反转 2017-07-09 关于 依赖注入 与 控制反转 的概念有些人觉得很难理解,最近在给别人讲这个概念的时候梳理了一个比较好理解的解释,而且我认为非技术人员也应该 ...

  6. 简单解释什么是 依赖注入 和 控制反转 1

    关于 依赖注入 与 控制反转 的概念有些人觉得很难理解,最近在给别人讲这个概念的时候梳理了一个比较好理解的解释,而且我认为非技术人员也应该能听的懂,因此分享给大家,希望下次你在给别人讲的时候也能讲的明 ...

  7. Spring的IOC(依赖注入和控制反转)

    Spring框架面试笔试必问之一!非常重要也非常强大,说实话一开始仿照着Spring MVC配置搭建起来,再写几句增删改查,真的配不上叫做学会了那个框架.框架是N种优秀的设计模式和一些很高深的技术组合 ...

  8. Spring的依赖注入和控制反转很难理解?一文搞定

    [用了这么久的Spring,一直没有理解好Spring的依赖注入和控制反转,以前看视频也没有老师讲清楚这个问题,今天终于刷到一个老师把这个问题讲清楚了,跪服大佬~~~] 孙哥说Spring5 全部更新 ...

  9. 依赖注入和控制反转的区别

    控制反转:创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理. 依赖注入:创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现. 依赖注入和控制反转是 ...

最新文章

  1. 沈航计算机复试刷人,过来人的血泪教训:复试被刷原因大盘点
  2. 工厂用抽象类比接口_用简单的现实类比解释硬编码概念
  3. 用java建一个类_利用JAVA创建一个类。
  4. Canal实时同步数据到RocketMQ
  5. python自动化运维快速入门-Python自动化运维快速入门
  6. Android studio 报错:Manifest merger failed xxx
  7. webUI自动化一元素定位
  8. 物联网操作系统Hello China V1.76(PC串口版)版本发布
  9. CentOS6.5安装nginx1.5.8时出现“cp: conf/koi-win 与/usr/local/nginx/conf/koi-win 为同一文件”的解决方法...
  10. 在quartusii如何设计出一个 3 位的十进制加法计数器的原理以及它的设计电_从算盘到计算机,从十进制到二进制,人类计算能力的提升...
  11. 整数输入有理循环小数 1/7 = 0.142857142... 是个无限循环小数。 任何有理数都可以表示为无限循环小数的形式。 本题目要求即是:给出一个数字的循环小数表示法。...
  12. GroovyHelp方便查看java api
  13. 第十一章 面向对象设计
  14. 我分析了100篇文章,总结出5点头条号推荐机制真相
  15. python软件工程师月薪-软件工程师薪水知多少?
  16. ipsec VPN 技术介绍(基础篇一)
  17. 基于树莓派GPIO口和光电传感器的障碍物检测
  18. mac磁盘工具制作dmg映像文件
  19. java实现分布式项目搭建的方法
  20. 两只蚊子的感人情感故事

热门文章

  1. idea打开项目慢怎么办?
  2. aboboo 上一句 快捷键_Word快捷键大全
  3. 解决微信小程序 picker 模式日期,设置默认当前时间
  4. java comet_用java实现comet,基于 HTTP长连接的实现,用于从服务端实时发送信息到客户端...
  5. 在一个无序的int数组上构建一个最小堆的时间复杂度_漫画:寻找无序数组的第k大元素(修订版)...
  6. mybatis清除一级缓存的几种方法
  7. Spring(4)——面向切面编程(AOP模块)
  8. java-Transient关键字、Volatile关键字介绍和序列化、反序列化机制、单例类序列化
  9. 使用基于注解的mybatis时,利用反射和注解生成sql语句
  10. Java并发编程(4):守护线程与线程阻塞的四种情况