[软件设计] 控制反转(Inversion of Control)随想
写这篇文章的初衷是在写Angular中的依赖注入(Dependency Injection)的时候,想该如何解释一下依赖注入这个概念呢? 最早接触到这个概念还是在学习Java中Spring框架的时候(估计好多开发人员都是这样的吧,来握个手),那时候它是作为Spring框架的一大卖点来介绍的。当时普遍存在一个误解,那就是控制反转和依赖注入是一件事的两个说法。这篇文章的目的之一也是为了来阐述一下这两者的联系和区别。 那么,我们来看看控制反转到底是何方神圣? 控制反转是干嘛的提起控制反转,就不得不提一下软件设计上的好莱坞原则(Hollywood Principle)。 好莱坞原则又是个啥?原文是”Don’t call us,we’ll call you”。直译过来就是”不要打电话过来,我们会打给你”。 那么在控制权被反转之前,我们有什么需要都要主动地去和相关人员进行沟通,这个过程是一个拉取消息的过程(Pull)。在控制权反转之后,我们需要做的就是好好等着,祈祷相关人员快点来找我们,很显然这是一个推送消息的过程(Push)。 在开发领域,从前的面向过程编程,就是采取的这一模式,首先定义一个main函数,在这个main函数里面定义所有的参与者和与它们之间的交互过程,一点都不能偷懒。需要用这个对象?自己去new!需要用那个库函数?自己去主动调用!那个时代的开发人员,就像是一个远古时代的人类,所有的干活累活都要一手包办。没法方便快捷地做他真正想处理的事情,想做顿饭?先去砍柴吧!没水了,去井里打啊!等一切就绪,才能开始做饭。这是一个多么低效率的生产方式。 而现代的面向对象编程,将上述的工作流程大大改观了。我们有各种适用于不同场景下的框架和设计模式,这些事物帮我们搭建好了一个整体架构,这个架构用于准备一些基本而普遍需要的基础物资。还是拿做饭这个例子,现在的人几乎都不会去砍柴打井水了,天然气自来水直接作为基础设施提供给你,你需要做的真的就只是”做饭”这一件事。而反映到软件框架中,就是框架已经给你准备好了main函数和其它各种基础功能,你需要做的就是专注于你的业务逻辑,把这些逻辑定义在正确地,符合框架规范的地方。你的逻辑加上框架里面那些已经定义好的可以复用的逻辑,就构成了我们生活中那些有血有肉的应用程序。 这就是控制反转。结合我们的生活经验看,一点也不复杂不是吗? 正是因为软件框架和设计模式所制定的游戏规则,我们才可以将各种软件功能封装成一个一个的模块,否则没有这个游戏规则,如何封装? 而这,就是控制反转的精髓所在。 再回过头来看看控制反转的设计目标: 是不是有种茅塞顿开的感觉呢? 几个遵循控制反转的事物说了这么多”大道理”,还是要举几个栗子的! 看的好像很高深的样子,下面就用大白话来撕下它们的伪装: 看了上面的大白话,再想想好莱坞原则,能够理解为什么说控制反转和它是一样一样的? 以上的共通之处想必大家也看出来了:填坑。这也是软件发展乃至人类社会发展的必由之路和康庄大道,一切规范化,一切规模化,一切流水线化。不需要你想太多,不需要你搞出什么花样,老老实实填坑就能让这个世界更美好! 等等,从上面的解释来看,工厂模式和依赖注入的意思不是根据需要静态/动态地去找坑嘛?很填坑有毛关系啊?也许对于工厂模式和依赖注入这样比较隐蔽的控制反转概念产物,填坑似乎有些牵强,我自己最初在考虑这个问题的时候,也陷入了一阵思考。为什么工厂模式和依赖注入会和填坑有关系呢? 请注意,这个坑确实有点隐蔽,但是深入思考一下也并不难看出它的真面目。请问你要找的坑是谁来填的呢?谁来填的呢?谁来填的呢?还不是你自己!只是你给这个坑根据其特点(接口)还准备了几个用于替换的坑,用于应对业务的复杂性罢了。正所谓”不识巨坑真面目,只缘身在此坑中”。 由控制反转所想到的毫无疑问,控制反转是非常重要的软件设计思想。 程序是能够改变人类生活方式,能够改变世界的,因为软件设计中蕴含的思想和规则也是这个世界奉行的思想和规则。人类从原始社会一步一步迈入如今的文明社会,这个过程也是一点点产出符合控制反转精神新事物的过程。从前没有职业的区别,一个人什么都干,也不管你擅长什么,所以每个人都需要干很多重复性的事情,产出很低。个人的产出低于是导致了整个社会的生产率低下。而每个人的性格不同,导致在面对相同的事物时所思所想不一样,于是产生了兴趣,在兴趣的催化下,会更加热衷于某些事情。而他的后代在他的言传身教之下,自然也对这类事情更加娴熟,于是乎职业和社会分工就出现了。职业的诞生,从控制反转这个角度上而言,就是让每个人专注于自己的职业目标,不需要考虑生活中的其它问题是如何解决的,你的这些问题总会有别的职业来帮你解决。通俗一点来说就是,专注于填属于你的坑。 但是,这还没完。社会进步的体现之一是职业的不断细分再细分。以前说隔行如隔山,卖包子的不懂隔壁裁缝是怎么做出来一件衣裳的。现在的情况是即便同属一个行业,也不清楚对方在做什么的情况比比皆是,以前互联网不发达的时候,也许就只有一个岗位叫程序员,负责和计算机相关的所有事务,而如今只说一个程序员已经没有辨识度了,甚至你说自己是后台开发,专业一点的人还会接着问,你是开发Web后台呢,还是大数据后台呢,还是游戏后台呢?一个后台开发就已经衍生出了数量众多了细分领域,你要让一个Web后台马上去开发游戏后台,那是不可能的。通俗点来描述这个问题,也就是随着这个坑的人越来越多,各种填坑姿势越来越丰富,导致这个坑也发生了分化,演化成了很多个小坑。但是作为个体,你还是要专注于填属于你的那一个坑。毕竟前提并没有变化,你的其它需求还是有别的职业来帮你解决。 而这些坑的出现,都是建立在实际需求之上的,所以人类的发展其实是一步一个脚印,在学习中总结,在实践中探索。不谈实际的坑都不是好坑,因此几十年前是绝对没有职业叫做什么虚拟现实游戏工程师的,你要说个虚拟现实别人还会说你脑子坏了。时过境迁,现在这个职业可是比较热门的噢。所以坑也不是说越多越好,弄出那么些没用的,不符合情境的坑也是不对的,一定是要结合当下的环境来造坑。反映到我们的程序中,那么就是过度设计是错误的!这是不是和高德纳的名言”过早优化是万恶之源”有异曲同工之妙呢。过度设计和过早优化就是在挖一些也许永远都用不上的坑,这些坑可能真的会”坑”你。现在有好多开发人员有一种比较激进的开发方针,不顾项目的业务情况,不顾项目的规模大小,不顾团队的技术储备情况。一上来就需要是各种高大上的玩意,要开发个Hybrid App,你要是不用一下最新最火的React Native都不好意思跟人家打招呼。什么?你还在用Ionic这种老掉牙的框架!Ionic不好!最近React Native可火了。反问Ionic为啥不好,说说看?一般情况是答不出,很显然很多人都搞不清楚这两个框架究竟有什么特点和各自的长短处。上来一个后台的项目,不管业务逻辑是什么,不管并发量和复杂度并不高的现实,先把各种时髦框架搭好再说,管它用不用的上,先来个消息队列吧,但是问一下为什么要用这个,相比最原始最简单的线程池有什么好处?对于当前的业务场景有什么好处?等等,线程池怎么用?天哪噜,并发相关的最最最基础的设施都没用过,你跟我谈消息队列? 其实说这些并不是否认很多”技术向”的开发者们那颗热爱新技术,崇尚新技术的心。说实话,这是非常好的心态,是在你的程序人生上非常需要保持的心态。这是一个以光速发展的行业,没有这种心态,你真的离被淘汰就不远了。我想说的是,坑要一个一个填,填好了一个才能填下一个,就像游戏里面的技能树一样,你不点那些基础的你看不上眼的,是绝对点不了技能树上顶端的那个牛逼到一塌糊涂的绝技的。如果有哪个游戏设计了不用点下面的基础技能点就能够点绝技的,请告诉我,我想去体验一下(要花大量RMB的请不要联系我)!人生如戏,游戏里面的那些最浅显不过的道理,在我们的填坑生涯中怎么就被忽略了呢。 人类的发展在加速,这就意味着我们造坑的速度也在加速。众多框架的开发者使出浑身解数,集众坑之所长进化出了各种造型靓丽的坑,给它们穿上各种鲜艳的衣服,宣扬其各种伟大的特性,其实本质上就是吸引我们来填。但是请不要幻想能够一招致命,不要幻想什么21天精通Reactive Native,尽管这类噱头似的口号却总是有市场。人类的发展史是一部一步一个脚印,一个坑挖好继续下一个坑的成长史。作为人类的个体,你的一生就是一部微缩版的人类成长史。这个过程需要脚踏实地,但是这并不妨碍我们仰望星空。 基础的重要性,不言而喻。 参考资料控制反转Wiki (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |