理解依赖注入和控制反转
在了解lumen框架的时候有遇到这两个概念,当时看了觉得模模糊糊地明白了,但是上周在上课时发现还是没
理解透,又重新梳理了解了下,总算有点明白了。
基本定义和关系
首先明白几个定义,然后理清他们之间的关系。
依赖反转原则(Dependency inversion principle,DIP)
是指一种特定的解耦(传统的依赖关系创建在高层次上,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象。
控制反转(Inversion of Control,缩写为IoC)
是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
依赖注入:依赖注入是种实现控制反转用于解决依赖性设计模式。一个依赖关系指的是可被利用的一种对象(即服务提供端) 。依赖注入是将所依赖的传递给将使用的从属对象(即客户端)。该服务是将会变成客户端的状态的一部分。 传递服务给客户端,而非允许客户端来建立或寻找服务,是本设计模式的基本要求。
依赖查找:依赖查找更加主动,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态
容器:容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。
反射:反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。
依赖反转、控制反转都是设计思想,是一种设计意识,指引方向。
依赖注入、依赖查找是设计模式,用来实现上面两个思想的实现方法。
容器可以理解为一种数据结构,是具体的编程方法。方便管理不同的类在一起管理。
反射是语言层面的特性,在代码运行的过程中,根据运行的中间状态来动态生成对象,让程序更灵活,简练。
依赖反转、控制反转是设计思想,依赖注入、依赖查找是实现思想的设计模式,使用容器和反射功能,能够更好地实现两种设计模式。
用途和实例
上面理顺了几个定义和他们之间的关系,再看下知道这些关系能有什么用途呢?
明白了上面的关系,就知道控制反转是思想,其他下层的概念是实现这种思想的途径。这里说的用途就是这种思想的用途。
控制反转、依赖反转的用途,就是解耦,方便扩展,带来的好处就是代码易扩展、测试、功能更稳定等。
例如做日志组件,日志可以记录到磁盘、数据库、udp发包到远程。
按照最直观的想法,在日志类里建立一个磁盘、数据库、udp三个媒介类,根据传入参数的不同选用不同的类进行调用。
这样做使日志类依赖底层存储媒介的实现,如果底层增加了tcp媒介,那么要修改日志组件内的代码,造成了耦合,只要有修改,就有引入bug的风险,容易把已有的功能影响。
运用控制反转思想,把磁盘、数据库、udp三个媒介类在抽象出一层writer接口,每个类都按照接口的要求实现,在日志类里都和抽象的接口打交道,实现日志类时传入要实现的类的类型就可以了。
到这步就已经有了控制反转的思想了。
但怎么能更好地实现这种思想呢?
一种是日志的构造函数里new出每个媒体类,第二种是传递媒体类的引用,在外部new好后传进来。依赖注入说的就是第二种。以参数的形式传进来。
优点是新增类型不用修改构造函数;缺点是要做一些判空处理。
还有一种方法是依赖查找,就是在需要具体媒体类的时候,根据关键字找出一个类,实现的方法可以是在内部建立一个类的关键字和类实例的数据结构,通过关键字找到一个类的实例来执行。
容器可以是一个存储类的数据结构,可以用类的名字的字符串,来找到一个执行功能的类,来创建和执行。
反射是实现的一种方法,能够在程序运行过程中,根据程序运行中间的数据,灵活地产生出要执行的类,来实现依赖查找。
小结
上面的描述更多地是把几个概念分类,描述功能,要想应用自如,还要参考具体项目实现的代码,动手实践。
参考
https://zh.wikipedia.org/wiki/%E4%BE%9D%E8%B5%96%E5%8F%8D%E8%BD%AC%E5%8E%9F%E5%88%99
https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC