依赖倒置(DIP),控制反转(IoC)与依赖注入(DI)
DIP,IoC与DI概念解析
依赖倒置
DIP(Dependency Inversion Principle)
DIP的两大原则:
1、高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
2、抽象不应该依赖于细节,细节应该依赖于抽象。
具体来讲,依赖倒置的核心思想是针对接口而不是实现编程。
应用DIP可以降低模块之间的耦合度,只要接口保持稳定,模块可以独立演化而互不影响。
控制反转
IoC(Inversion of Control)
通常情况下,class A依赖于class B,或者应用DIP之后依赖于Interface B,那么在运行时,我们必须自行主动的去实例化Interface B接口的实现类实例,然后将其引用传递给Class A,在传统的编程模型下,我们经常这样干。这样耦合度仍然很高,我们必须知道所依赖的实现类的一些细节。
而IoC则是将实例化被依赖模块的责任交出去,不再主动去做依赖装配工作,这样我们就可以彻底的只针对接口编程,而无需关心具体的实现。
IoC容器成为一个系统的对象容器和粘合剂,它负责创建对象的实例,并按照它们声明的依赖关系把它们粘合起来共同工作。通过配置文件或注解的方法,IoC容器会自动的满足模块之间的依赖关系,而无需我们再主动去处理依赖关系,只要被动接受就可以了。
这种依赖关系的满足由主动实现到被动接受的转变,就是所谓的控制反转了。
IoC与好莱坞原则(Don’t call me,i’ll call you!)比较相似。
依赖注入
DI(Dependency Injection)
依赖注入是实现控制反转的主要方式,另一种方式是依赖查找。
两者的区别在于,依赖注入是被动的接收对象,而依赖查找是主动索取响应名称的对象,获得依赖对象的时间也可以在代码中自由控制。依赖查找更加主动,在需要的时候通过调用框架提供的方法来获取对象,获取时需要提供相关的配置文件路径、key等信息来确定获取对象的状态。比如使用JNDI来查找资源。
依赖注入有以下几种实现方式:
1、接口注入或叫Type 1型注入。需要实现特定接口以供外部容器注入所依赖类型的对象。这里有一个写的比较好的例子。这种注入方式很少用到。
2、setter注入或叫Type 2型注入。实现特定属性的public set方法,来让外部容器调用传入所依赖类型的对象。这种注入方式是最常见的。
3、构造函数注入或叫Type 3型注入。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
4、注解注入。基于Java的注解功能,在私有变量前加“@Autowired”等注解,不需要显式的定义以上三种代码,便可以让外部容器传入对应的对象。该方案相当于定义了public的set方法,但是因为没有真正的set方法,从而不会为了实现依赖注入导致暴露了不该暴露的接口(因为set方法只想让容器访问来注入而并不希望其他依赖此类的对象访问)。注解注入是比较好的注入实现方式。
总的来讲,依赖倒置(DIP)是一种设计原则,控制反转(IoC)是一种处理对象间依赖关系的方式,与传统的主动方式正好相反,而依赖注入(DI)则是IoC容器实现控制反转的主要方式。
参考:
依赖注入那些事儿