什么是ioc_3.2.3什么是依赖注入*

本来,我希望将目前写得比较完整的章节贴出来,给学生参考。在贴到本文【3.2.3什么是依赖注入】时发现【1.2.3控制反转】还没有贴出来,又回头修改了IoC的内容并贴出来。我知道,很多读者已经看过各种关于DI、IoC和DIP的文章,可能一时间接受不了我写的内容。DI、IoC和DIP,我还会使用DI,【yqj2065都不敢使用控制反转(Inversion of Control、IoC)这个术语了(本来穿衣服是正常的,裸体太流行了,我不敢穿衣服出门。嗯,就是这种赶脚。】,DIP则是垃圾。


God 与Spring,不过是依赖抽象类型原则的使能工具。Martin Fowler在文章《IoC容器和依赖注入模式》中创造了“依赖注入”这一术语。

Martin Fowler(马丁·福勒),国际著名的OO专家,敏捷开发方法的创始人之一,现为ThoughtWorks公司的首席科学家。在面向对象分析设计、UML、模式、软件开发方法学、XP、重构等方面,都是世界顶级的专家.他著有几本经典书籍:《分析模式》、《UML精粹》和《重构》等。即使如此,本节仍然要板砖拍一下Martin Fowler的文章

IoC容器和Dependency Injection模式 - ThoughtWorks洞见​insights.thoughtworks.cn
d10c61a8c5946999e183d76888b2ce08.png

,说明Martin Fowler该文的不妥之处:

  • 错误解释IoC,将一个使能工具神秘化。
  • 没有明确定义依赖注入和服务定位器(Service Locator)

下面分析其《IoC容器和依赖注入模式》,由于依赖注入之外的服务定位器(Service Locator)放在后面章节,因此本节主要说明Martin Fowler该文的部分错误。

1.晦涩的介绍

该文章以“装配程序元素”为噱头,决定在其文章中使用术语组件。『组件将被作者无法控制的其他应用程序使用,但后者不能对组件进行修改。也就是说,使用一个组件的应用程序不能修改组件的源代码,但可以通过作者预留的某种途径对其进行扩展,以改变组件的行为』。其实组件不组件,在后面没有太多意义,用模块或类/类型都可以。

然后该文给出[一个简单的例子],该节的核心是『我们希望MovieLister类能够与MovieFinder的任何实现类配合工作,并且允许在运行期插入具体的实现类,插入动作完全脱离我(原作者)的控制。这里的问题就是:如何设计这个连接过程,使MovieLister类在不知道实现类细节的前提下与其实例协同工作。……所以,现在的核心问题就是:如何将这些插件组合成一个应用程序?这正是新生的轻量级容器所面临的主要问题,而它们解决这个问题的手段无一例外地是控制反转(Inversion of Control)模式。』

对于不知道开放封闭原则、针对接口编程和抽象依赖原则的读者,或许可以从其文字中隐隐约约获得某些启发。但是,对于理解抽象依赖原则的读者,可以非常简单明了地描述出Martin Fowler的意思:MovieLister/Client需要依赖一个抽象类型MovieFinder/IServer,“如何将MovieLister对象与特定的finder对象连接起来”,“MovieLister类既依赖于MovieFinder接口,也依赖于具体的实现类。我们当然希望MovieLister类只依赖于接口,但我们要如何获得一个MovieFinder子类的实例呢?”,啰啰嗦嗦地,

不就是要解决的如何初始化抽象类型的问题吗?或者说,解决依赖抽象类型原则的使能问题,而这就是[3.1工具类God]讨论的问题。

【Martin Fowler的晦涩的介绍,我不知道到底是因为这样写显得高深,还是因为他不能够/没有能力简明的说出要点。或许他使用插件(plugin)这个词能够导出他准备推出的注射/注入/ Injection,也说不定。】

2.错误解释IoC

由于商业因素,轻量级容器的作者喜欢用IoC吹嘘其容器。Martin Fowler意识到其中的问题,但是偏偏他本身不懂什么是IoC,读者请先回顾

严千钧:什么是控制反转(Inversion of Control,IoC)​zhuanlan.zhihu.com

。正因为如此,该文嘲笑几位轻量级容器的作者,"我的轿车是与众不同的,因为它有四个轮子"显得可笑,不过是五十步笑一百步。Spring DI容器如同God,仅仅是工具箱,既然IoC是框架所共有的特征,作为工具箱的DI容器就和框架/控制反转IoC一点关系都没有。DI容器完全是一个自行车,只有两个轮子。

正因为他不懂IoC,他提出一个愚蠢的问题:“问题的关键在于:它们反转了哪方面的控制?”,如果读者上网搜索,会发现:在网络文章中有大量的对控制反转加以“说文解字”的文章。说文解字的根源在于Martin Fowler的一句话,“它们反转了哪方面的控制”?

他写到:“我第一次接触到的控制反转针对的是用户界面的主控权…. 早期的用户界面是完全由应用程序来控制的,你预先设计一系列命令,例如输入姓名、输入地址等,应用程序逐条输出提示信息,并取回用户的响应。而在图形用户界面环境下,UI框架将负责执行一个主循环,你的应用程序只需为屏幕的各个区域提供事件处理函数即可。在这里,程序的主控权发生了反转:从应用程序移到了框架。”。这就暴露他不懂什么是IoC

正如[1.2.3控制反转]所言,IoC是框架所共有的特征,那么各种各样的框架都起到主程序的角色。但是IoC甚至不涉及代码的变化,换言之,Martin Fowler可以反工程地把框架代码复制粘贴为应用程序的一部分,从而不需要框架和IoC在代码不变化到情况下,讨论框架和IoC才比较合理。另外,反转不是“变化”,各种各样的框架作用不同,引起的变化不同,不要认为变化的部分就反转了。我今天用打火机点烟,明天有人帮我点烟,是不是出现反转?那里反转了?这样讨论反转很无聊。

退一万步讲,即使不懂什么是IoC也无所谓,但是Spring DI容器是框架吗?为什么我要先介绍God,为什么将DI的概念形容为伸手-等待,就是希望程序员清楚地知道Spring DI容器如同God,仅仅是工具箱。

除非程序员要定制或扩展Spring,一般情况下Spring的DI容器不是框架-骨架式方案,而是完整的方案。使用框架,应用程序员至少要编写一个@Override,这是判断使用的库是框架还是工具箱的唯一标准。

3. 什么是依赖注入?

Martin Fowler写到:『Dependency Injection 模式的基本思想是:用一个单独的对象(装配器)来获得MovieFinder的一个合适的实现,并将其实例赋给MovieLister类的一个字段』。

显然,God就是标准的合适的装配器,Client的代码中通过God(配合配置文件)获得IServer的一个合适的实现,而且该IServer对象不仅可以在Client作为一个成员变量,还可以作为函数的局部变量或参数。

问题是,按照他的说法, 静态工厂是不是Dependency Injection?

该文随后的图,按照God看,依赖关系不对。

8ba4d619f12b9d8c57dab517c30e468b.png
  • MovieLister依赖抽象类型MovieLister和装配器Assembler。
  • Assembler不依赖任何类型。因为它不知道使用者是MovieLister,它也不知道创建的是MovieFinder对象,它仅仅知道创建了一个Object对象(除非装配器Assembler是静态工厂)。

Martin Fowler有一句话写的很好:『依赖注入的最大好处在于:它消除了MovieLister类对具体MovieFinder实现类的依赖』,它应该在该文的最开始就说明:依赖注入工具就是抽象依赖原则的使能工具

4. 什么是服务定位器(Service Locator)?

不太清楚Martin Fowler关于依赖注入模式和服务定位器(Service Locator)模式地介绍。『无论使用哪个模式,应用程序代码都不依赖于服务接口的具体实现。两者之间最重要的区别在于:具体实现以什么方式提供给应用程序代码。使用Service Locator模式时,应用程序代码直接向服务定位器发送一个消息,明确要求服务的实现;使用Dependency Injection模式时,应用程序代码不发出显式的请求,服务的实现自然会出现在应用程序代码中,这也就是所谓控制反转。』

上一节中,将DI的概念被形容为伸手-等待。Spring不同于God,God在源代码的每一层依赖关系中,都需要使用一次;而Spring中,多层依赖关系的所有对象的创建,“等待”那一次ApplicationContext(或其他类似功能的类)的出现。

是否站在Demo的位置看,Spring是服务定位器;站在AA1的位置看,Spring是依赖注入?(实在没有搞清楚,服务定位器和依赖注入的区别)


What's the difference between the Dependency Injection and Service Locator patterns?​stackoverflow.com
73940c3cc4169aceba1839a34b0b9615.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值