反射是实现控制反转和依赖注入 控制反转的根本基础,对吗

理解依赖注入与控制反转 - 简书
<div class="fixed-btn note-fixed-download" data-toggle="popover" data-placement="left" data-html="true" data-trigger="hover" data-content=''>
写了138171字,被196人关注,获得了216个喜欢
理解依赖注入与控制反转
依赖注入与控制反转
依赖注入 当我第一次接触这个词的时候,我是有些丈二和尚摸不着头脑的,至今我也是感到比较困惑的,所以今天我们来探索一下Laravel中的依赖注入(dependency injection) 来好好的理解它。
控制反转 第一印象是好深奥的名词,看上去好像是说反向控制?不懂?那就理顺之!
什么是依赖
没有你我就活不下去,那么,你就是我的依赖。
说白了就是:
不是我自身的,却是我需要的,都是我所依赖的。一切需要外部提供的,都是需要进行依赖注入的。
我们用代码来描述一下:
class Boy {
protected $
public function __construct(Girl $girl) {
$this-&girl = $
class Girl {
$boy = new Boy();
// E Boy must have girlfriend!
// so 必须要给他一个女朋友才行
$girl = new Girl();
$boy = new Boy($girl); // Right! So Happy!
从上述代码我们可以看到Boy强依赖Girl必须在构造时注入Girl的实例才行。
那么为什么要有依赖注入这个概念,依赖注入到底解决了什么问题?
我们将上述代码修正一下我们初学时都写过的代码:
class Boy {
protected $
public function __construct() {
$this-&girl = new Girl();
这种方式与前面的方式有什么不同呢?
我们会发现Boy的女朋友被我们硬编码到Boy的身体里去了。。。 每次Boy重生自己想换个类型的女朋友都要把自己扒光才行。。。 (⊙o⊙)…
某天Boy特别喜欢一个LoliGirl ,非常想让她做自己的女朋友。。。怎么办?
重生自己。。。扒开自己。。。把Girl扔了。。。把 LoliGirl塞进去。。。
class LoliGirl {
class Boy {
protected $
public function __construct() {
$this-&girl = new Girl();
// sorry...
$this-&girl = new LoliGirl();
某天 Boy迷恋上了御姐.... (⊙o⊙)… 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 $
public function __construct(Girl $girl) {
$this-&girl = $
$loliGirl = new LoliGirl();
$vixen = new Vixen();
$boy = new Boy($loliGirl);
$boy = new Boy($vixen);
Boy很高兴,终于可以不用扒开自己就可以体验不同的人生了。。。So Happy!
因为大多数应用程序都是由两个或者更多的类通过彼此合作来实现业务逻辑,这使得每个对象都需要获取与其合作的对象(也就是它所依赖的对象)的引用。如果这个获取过程要靠自身实现,那么将导致代码高度耦合并且难以维护和调试。
所以才有了依赖注入的概念,依赖注入解决了以下问题:
依赖之间的解耦
单元测试,方便Mock
=。= 前面的依赖注入居然需要我们手动的去注入依赖,做为程序员的我们怎么可以容忍这种低效的注入方式,好吧,我们先来了解一下IOC的概念.
控制反转 (Inversion Of Control, IOC)
控制反转 是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection, DI), 还有一种叫"依赖查找"(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
也就是说,我们需要一个调控系统,这个调控系统中我们存放一些对象的实体,或者对象的描述,在对象创建的时候将对象所依赖的对象的引用传递过去。
在Laravel中Service Container就是这个高效的调控系统,它是laravel的核心。
下面我们看一下laravel是如何实现自动依赖注入的。
laravel中的依赖注入
现在我们看文档给的例子应该就不难理解了:
namespace App\J
use Illuminate\Contracts\Mail\M
use Illuminate\Contracts\Bus\SelfH
class PurchasePodcast implements SelfHandling
* The mailer implementation.
protected $
* Create a new instance.
* @return void
public function __construct(Mailer $mailer)
$this-&mailer = $
* Purchase a podcast.
* @return void
public function handle()
In this example, the PurchasePodcast job needs to send e-mails when a podcast is purchased. So, we will inject a service that is able to send e-mails. Since the service is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the mailer when testing our application.
说到laravel中的依赖注入,我们不得不了解laravel的Service Container
服务容器 (Service Container)
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.
从介绍不难看出服务容器就是控制反转的容器,它就是前文说到的调度系统。实现依赖注入的方式可以是在构造函数中或者setter方法中。
如果我们仔细研究了Service Container我们就会发现laravel的服务容器中只存储了对象的描述,而并不需要知道如何具体的去构造一个对象,因为它会根据php的反射服务去自动解析具体化一个对象。
在计算机科学中,反射是指计算机在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用来比喻说,那种程序能够“观察”并且修改自己的行为。
支持反射的语言提供了一些在低级语言中难以实现的运行时特性。这些特性包括
作为一个第一类对象发现并修改源代码的结构(如代码块、类、方法、协议等)。
将跟class或function匹配的转换成class或function的调用或引用。
在运行时像对待源代码语句一样计算字符串。
创建一个新的语言字节码解释器来给编程结构一个新的意义或用途。
PHP实现的反射可以在官网文档中进行查看:
$reflector = new ReflectionClass('App\User');
if ($reflector-&isInstantiable()) {
$user = $refector-&newInstance(); //in other case you can send any arguments
laravel的服务容器的build方法中需要通过反射服务来解析依赖关系,比如说construct函数中需要传递的依赖参数有哪些? 它就需要用到如下方法:
$constructor = $reflector-&getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
if (is_null($constructor)) {
array_pop($this-&buildStack);
return new $
$dependencies = $constructor-&getParameters();
现在我们应该对laravel如何实现依赖的自动注入有点想法了吧?来整理一下疑问:
如何实现依赖的自动注入? (控制反转,利用反射)
依赖注入需要哪些东东? (整理依赖关系[ construct | setter ],还要解析依赖传递引用)
怎么解析依赖?
你可能会问为什么要问怎么解析依赖?解析依赖肯定是要用到反射的啦,反射,你知道类名不就可以直接解析了吗?
其实。。。不是这样的。。。(@ο@)
很多时候我们为了提高代码的扩展性和维护性,在编写类时依赖的是接口或抽象类,而并不是一个具体的实现类。明白了吗?依赖解析的时候如果只解析到接口或抽象类,然后利用反射,那么这个依赖肯定是错误的。
那么我们就需要在调度系统中注入相关依赖的映射关系,然后在需要的时候正确的解析关系。
比如说, 喂, 我需要一个 A, 你别给我 B 啊。
$container-&bind('a', function () {
return new B();
// just this for you
$a = $container-&make('a');
依赖注入是控制反转的一种实现,实现代码解耦,便于单元测试。因为它并不需要了解自身所依赖的类,而只需要知道所依赖的类实现了自身所需要的方法就可以了。你需要我,你却不认识我/(ㄒoㄒ)/~~
控制反转提供一种调控系统,实现依赖解析的自动注入,一般配合容器提供依赖对象实例的引用。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
Write the Code, Change the World, 改变世界从编程开始, 收集编程相关的干货
· 12196人关注
使用Laravel开发的技术分享,欢迎各种干货。
· 270人关注
从今天起,继续接触Web叭
· 246人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:博客访问: 784576
博文数量: 248
博客积分: 10010
博客等级: 上将
技术积分: 2415
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
昨天经过一朋友的SPACE,看到有关于控制反转的讨论,一时技痒,写下一段留言,完后由于比较长的时间没接触这几个单词,因此又去查了些资料,重新整理了一下,跟大家一起讨论。
&& 整理之前,首先要说说“依赖”,什么是依赖,依赖就是关联,UML中定义的“关联”是最泛泛的一种关系,表现为两个类图之间有根线就有关联,我个人理解成,在C/C++中,A include了另一个头文件B,JAVA/.Net中A using了另一个package或者unit B,则两者就有了关联,A依赖于B,因为假设没有依赖关系,A为啥要include B?肯定了发生了某种调用(B.Call())或者引用(如B做为某个类变量或者参数变量)。所以偶把这个理解成依赖。
&& 网上讨论的假设B发生变化那A也发生变化成为依赖,偶觉得可能会有一定的误导,因为假设变化的是B内部,接口不变,那A为什么要变?或者B增加一个接口A不调用,A也不用变,但是A依然依赖于B。
&& 这是关于依赖,接下来是关于标题三个名词,在这里不想一个个去解释,因为那可能有种就事论事的感觉,想跟大家讨论一些比较本质的东西。
&& 在面对一个复杂事务的时候,我们的处理办法是什么?毫无疑问是分解,想想那些日理万机的领导,凡事不论巨细都要过问的话那是不可能,因为个人的精力有限,而复杂度是随着规模的增大而呈数量级的变化的,所以领导怎么处理?分解,分成市场总监,财务总监,技术总监,行政总监等一个个角色,每个角色负责一块,到时候跟领导汇报各自的问题就OK了,领导来做决策。
&&&&& 以软件来类比的话,这里的总监就是一个个模块,汇报就是OO中的接口(Interface),领导就是框架,把全部的模块串起来完成一个既定的大目标(如实现某个方案)。那工程师或者财务人员呢?毫无疑问就是一个个具体的CLASS了,是实现具体某个功能的执行体,如一项编程工作或者整理出某个报表。
&&& 由此可见,每天在我们周围发生的这些事情,这些公司内部的一些行为都可以映射成整个软件构架。那么从公司的这种组织行为我们可以得到什么样的思考?首先有了分解我们可以降低一些的复杂度,但接下来呢,软件最复杂的在于什么?在于变化。公司也一样,外界要面临重重生存压力,内部可能会有一些公司层面的或者个人层面的问题,甚至人员跳槽也会带来一定的风险,那公司怎么处理? 隔离。把容易变化的跟不容易变化的相对稳定的隔离开来,这样就能做到控制影响到最小。那么隔离通过什么来实现?抽象。为什么?因为抽象是相对稳定的。
&&& 这里举个比较好笑的例子:一个即将做领导的儿子问曾经做领导的父亲怎么才能平步青云,父亲说你不能说假话,因为老百姓会不答应,也不能说实话,因为领导会对你有意见,儿子思索良久问:那我该说什么? 父亲意味深长的说:空话
&& 笑话不但好笑,还能反映一定的道理,为啥空话这么有用,因为他是抽象的,而抽象不涉及到一些具体的数据或者事务,因此他是稳定的,是不容易变化的,同时基本上也是正确的。所以我们经常在公开场合听到类似的话“我们要团结同志,努力进取,提高工作效率,降低工作成本。。。”你能说这是错的吗,当然不能,所以既然是非常稳定的对的,所以这种依赖就很可靠啦。
&&&公司也一样,假设领导依赖于工程师的能力,成天问这个问那个,那如果有一天工程师跳槽了怎么办?领导处理的都是一些非常重要宏观的事务,不可能因为某个小小的工程师而产生什么大的影响,因此他不会直接依赖工程师,而是依赖于一个叫技术总监这样的一个抽象。如果工程师离职,那换个工程师继续替代他以前做的事情就行了,而且都实现的是技术总监规定好的接口,这样对领导就没什么影响了,也只有这样变化就被隔离开来了。
&& 再反过来想想软件,其实上面描述的都是一些对软件而言非常有意义的做法,OO中非常重要的一点就是模块之间依赖于抽象的接口,而不是具体的实现,为啥,因为抽象是相对稳定的。一个IO他必然就有READ/WRITE这两个抽象,至于具体是磁盘还是键盘,那是下面的实现不同了,通过这种构架,能保持软件的弹性与可维护性。
&& 由公司的行为还有一点容易受到启发的就是公司的组织构架,公司的层次可以映射成软件的分层,领导是框架层,下面通过一个个接口去管控一个个CLASS。我们设计软件的时候毫无疑问也应该这样。设计好框架设计接口,设计好接口再去调用一个个的API或者CLASS去实现某一个具体的实现比如数据库的读写或者SOCKET数据的收发。每个地方有自己相对对立的职责,各尽其职。如果上来就是一个个API,那相当于一大群工程师既做商务谈判,又去编码,那就杂乱无章啦。这样的结果感觉都是一样:混乱。
&& 最后言归正传,谈谈上面的三个名词,依赖倒置DIP(Dependency Inversion Principle)在马丁大叔的杰作《敏捷开发:原则,实践与模式》中描述的比较清楚,高层模块不应该依赖于底层模块,而应该两者都依赖于一个抽象,底层模块实现抽象。相信这点已经在上面讨论的比较清楚了,就好比尽管领导归根结底要依赖工程师来做事,但他不会直接依赖你,而是依赖于一个总监的抽象。这就是倒置,哪里倒了?这种依赖关系倒了,引入了一个新的中间层,一个抽象。以前传统的过程设计中是从上到下的一条依赖线,现在是平的一条领导到总监,然后是一条从下往上的工程师到总监的关联线。
& 控制反转(Inversion of Control)其实有点类似,主要是OO中提出了框架的概念,什么是框架,按王氏兄弟的《道法自然》中的描述,主要是一个动态的环境体,可以处理一些比较复杂的事务或者逻辑,跟类库静态的行为不大一样,类库都是一个个等待别人调用的服务。 那么控制体现在什么地方?传统的做法,我们在自己的程序中调用一个个类库去完成一个个功能,类库是我们的执行体,但是逻辑算法等是自己实现的,这就是自己的控制,但框架不一样,逻辑算法都是它来实现,我们只要提供它几个需要的接口或者执行体就可。这就是反转,控制在框架这边了,主要是简化了一定的工作量,对于一些常见的业务场景不需要自己去重复实现罢了。那么控制反转主要应用的是模板方法等模式,个人觉得观察者模式是一个比较典型的控制发转的实例,因为论询observer是subject这边实现的一个逻辑,而observer 只要实现notify这样一个接口即可。所以其实也没什么。
&& 依赖注入(Dependency Injection)其实相比以上两者应该不是一个层次的概念,主要是表现为利用构造函数或者接口来完成具体的工作类的绑定而已,这么想好了,比如要完成一个开发工作,可以让总监自己去指定工程师甲来完成这个工作,但为了更大的弹性,可以让总监提供这么个接口
AssignJob(Engineer engineer) {engineer.do();}
这样总监可以默认让甲去完成这个工作,但如果某种原因例如甲请假,那么就可以通过这个接口去让乙去做这件事情,这样在发生变化的时候就有弹性了。顺便提一下,软件多数通过CONFIG来达到更大的灵活性,由于.NET/JAVA等引入了反射的概念,可以在RUNTIME期间动态的去创建类,这个功能就很强大了,参考如上的业务需求,我们就可以把类名放在CONFIG中,通过反射去加载不同的类从而完成不同的实现。这也是很多框架(如structs)的最基本的做法
&&& 以上是一些个人看法,感觉一些OO的名词听起来玄乎,其实也就那么回事,只要掌握好OO的几个基本原则,其实基本上都可以推导出来。呵呵。个人愚见,希望跟大家交流
&& 附上王氏兄弟的更精彩精辟的讲解:
阅读(1297) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。第三阶段测试(带答案)_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
第三阶段测试(带答案)
上传于||暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩5页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
taodengwen@126推荐阅读:
阅读(24595)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'控制反转与依赖注入',
blogAbstract:'&
关于控制反转和依赖注入的文章和书籍很多,对其定义也解释的也仁者见仁,这里就不赘述了,这是本人(只代表个人观点)理解之后用通俗的例子和平淡的话词为您解释,希望对您有所帮助:
控制反转(IoC/Inverse&Of&Control):&& 调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
依赖注入(DI/Dependence&injection)&:&& 容器创建好实例后再注入调用者称为依赖注入。
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,。如果创建被调用者实例的工作不再由调用者来完成,而是由外部容',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:8,
publishTime:0,
permalink:'blog/static/',
commentCount:13,
mainCommentCount:13,
recommendCount:3,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 反射与依赖注入 的文章

 

随机推荐