案例解析依赖注入和控制反转

什么是依赖注入 依赖注入(Dependency Injection) , 是这样一个过程:某客户类只依赖于服务类的一个接口 , 而不依赖于具体服务类 , 所以客户类只定义一个注入点 。在程序运行过程中 , 客户类不直接实例化具体服务类实例 , 而是客户类的运行上下文环境或专门组件负责实例化服务类 , 然后将其注入到客户类中 , 保证客户类的正常运行 。
什么是控制反转 在解释什么是控制反转的之前我们先引入上一篇博文一个博友在评论中提的问题:依赖注入和控制反转不是一回事吗?
在我看来 , 控制反转这种思想最终的实现要依赖与依赖注入这种实现方式 。控制反转只是把高低层的关系发生变化 , 以前底层模块在实现功能的时候可能会依赖于高层模块 , 通过控制反转可以让底层模块依赖于一个接口 , 如果这个时候高层模块要使用底层模块的话就必须
实现这个接口 , 然后通过依赖注入的方式把高层模块的实现类注册到底层模块中使用 。
有可能上面的解释大家比较懵 , 下面我会通过举例来进一步介绍控制反转这种设计模式 。
一个例子理解控制反转

案例解析依赖注入和控制反转

文章插图
我们暂把上图的框架成为“自动驾驶系统” , 现在“自动驾驶系统”已经拥有了自动开汽车、开飞机、开火车的功能了 , 你觉得已经很强大了 , 于是把这套系统卖给了某个公司 , 但是这家公司的业务不仅限于前三种交通工具 , 现在这家公司要实现驾驶者可以驾驶飞船 , 如下图所示

案例解析依赖注入和控制反转
文章插图
大家可以看到如果我们的“自动驾驶系统”要实现可以驾驶飞船的话 , 就需要驾驶者创建“飞船”的对象 , 这个时候我们的框架还是依赖于外部(因为飞船类在客户那边) 。这个就是我们常说的底层模块依赖于高级模块 。这种依赖肯定是不行的 , 随着客户的变化就要改动我们的框架 , 这种做法肯定不行 , 我们继续演变 。

案例解析依赖注入和控制反转
文章插图
现在我们的驾驶者并不直接依赖于某个具体实现类 , 而且依赖于接口 , 但是这个时候上图就暴露了一个问题 , 希望大家先不要看下面的文字 , 大家可以先思考下上图有什么问题 。(上图三个交通工具和接口的关系标识错了 , 应该是实现)
上图的设计虽然解决了不用New具体那个对象的问题 , 但是新的问题也随之而来:驾驶者到底使用哪个实现类?大家都知道接口是不能直接实例化的 , 能够实例化的只有接口的具体的实现类 。OK , 为了解决这个问题我们继续演变

案例解析依赖注入和控制反转
文章插图
上图我们使用工厂模式 , 这时候的关系是驾驶者依赖与工厂类 , 由工厂类具体去创建具体的实现类 。根据上图我们再看如果我们实现开飞船 , 那么它们之间的关系会发生什么样的变化(上图三个交通工具和接口的关系标识错了 , 应该是实现)

案例解析依赖注入和控制反转
文章插图
通过一系列演化 , 现在两者之间的关系已经彻底发生了改变 , 以前是底层模块(框架)依赖于高层模块 , 现在变成了高层模块依赖于底层模块 , 从上图可以看出 , 无论你是要开飞船还是开火箭 , 只要你实现了“交通工具”接口 , 那么我就可以在工厂类里面给创建出来 。这样一来不仅增加了我们系统的可扩展性 , 也提高了我们系统的整体稳健型 。
最后来总结一下到底什么是控制反转 , 我的答案已经在文章开头给出了 , 下面给出维基百科的答案:
【案例解析依赖注入和控制反转】 控制反转(Inversion of Control , 缩写为IoC) , 是面向对象编程中的一种设计原则 , 可以用来减低计算机代码之间的耦合度 。其中最常见的方式叫做依赖注入(Dependency Injection , 简称DI) , 还有一种方式叫“依赖查找”(Dependency Lookup) 。通过控制反转 , 对象在被创建的时候 , 由一个调控系统内所有对象的外界实体 , 将其所依赖的对象的引用传递给它 。也可以说 , 依赖被注入到对象中 。
编辑:hfy

    推荐阅读