1 最初的时候new对象才能进行操作,耦合度比较紧
2.统一某种工具类继承某个类型的类
我们经常使用new关键字来实现两个组件之间关系的组合,这种实现方式会造成组件之间耦合。
为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson提出了IOC理论,用来实现对象之间的“解耦”。
这个办法就叫控制反转(Inversion of Control,缩写为 IoC),它不是一种技术,而是一种思想——指导我们设计出松耦合的程序。
控制反转从词义上可以拆分为“控制”和“反转”,说到控制,就必须找出主语和宾语,谁控制了谁;说到反转,就必须知道正转是什么。
你看,在紧耦合的情况下,XXX下命令的时候自己要通过 new 关键字创建依赖的对象;而控制反转后,老王要找的创建依赖的对象由容器负责,也就是说控制权交给了容器,是不是反转了呢?
依赖注入(Dependency Injection,简称 DI)是实现控制反转的主要方式
1)基于构造函数。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
2)基于 set 方法。实现特定属性的 public set 方法,让外部容器调用传入所依赖类型的对象。
控制权仍然掌握在主类里面,它决定传入哪个对象来执行对应的命令。
3)基于接口。实现特定接口以供外部容器注入所依赖类型的对象。
可能有人会把控制反转等同于依赖注入,但实际上它们有着本质上的不同:控制反转是一种思想,而依赖注入是实现控制反转的一种形式。
spring框架的操作:
当我们搞清楚控制反转和依赖注入的概念后,就可以顺带了解一下大名鼎鼎的 Spring 框架。控制反转是 Spring 框架的核心,贯穿始终。Spring 中依赖注入有两种实现方式:set 方式(传值方式)和构造器方式(引用方式)。
首先,我们需要在 pom.xml 文件中加入 Spring 的依赖项,代码如下所示:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
其次,我们将 Laowang 类修改为如下内容:
public class Laowang {
private Heshang saodiseng;
public Laowang(Heshang saodiseng) {
this.saodiseng = saodiseng;
}
public void mingling() {
this.saodiseng.saodi();
}
}
然后,我们创建一个 Spring 的配置文件 application.xml,内容如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="laowang" class="com.cmower.java_demo.ioc.Laowang">
<constructor-arg ref="saodiseng" />
</bean>
<bean id="saodiseng" class="com.cmower.java_demo.ioc.Xiaosan" />
</beans>
准备工作完成以后,我们来测试一下,代码示例如下:
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Laowang laowang = (Laowang) context.getBean("laowang");
laowang.mingling();
}
}
你看,我们将控制权交给了 IoC 框架 Spring,这样也可以完美的解决代码耦合度较紧的问题。
05、最后
总结一下:
1)控制反转是一种在软件工程中解耦合的思想,把控制权交给了第三方,在运行的时候由第三方决定将具体的依赖对象“注入”到调用类的对象中。
2)依赖注入可以作为控制反转的一种实现方式,将实例变量传入到一个对象中去。
3)通过 IoC 框架,类 A 依赖类 B 的强耦合关系可以在运行时通过容器建立,也就是说把创建 B 实例的工作移交给容器,类 A 只管使用就可以。
其他的总结:
所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
Ioc:控制反转:控制反转就是加将组件的依赖关系从程序内部提到外部来管理(思想:解耦)
DI:依赖注入;依赖注入是指将组件的依赖通过外部以参数的方式或者其他方式注入(实现方式)
依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建
并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应
用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。
简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度
简单易懂的例子:
现在,我们利用电脑主机和USB接口来实现一个任务:从外部USB设备读取一个文件。
电脑主机读取文件的时候,它一点也不会关心USB接口上连接的是什么外部设备,而且它确实也无须知道。它的任务就是读取USB接口,挂接的外部设备只要符合USB接口标准即可。所以,如果我给电脑主机连接上一个U盘,那么主机就从U盘上读取文件;如果我给电脑主机连接上一个外置硬盘,那么电脑主机就从外置硬盘上读取文件。挂接外部设备的权力由我作主,即控制权归我,至于USB接口挂接的是什么设备,电脑主机是决定不了,它只能被动的接受。电脑主机需要外部设备的时候,根本不用它告诉我,我就会主动帮它挂上它想要的外部设备,你看我的服务是多么的到位。这就是我们生活中常见的一个依赖注入的例子。在这个过程中,我就起到了IOC容器的作用。
通过这个例子,依赖注入的思路已经非常清楚:当电脑主机读取文件的时候,我就把它所要依赖的外部设备,帮他挂接上。整个外部设备注入的过程和一个被依赖的对象在系统运行时被注入另外一个对象内部的过程完全一样。
我们把依赖注入应用到软件系统中,再来描述一下这个过程:
对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办。
IOC中最基本的技术就是“反射(Reflection)”编程,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才决定到底是哪一种对象。只是在Spring中要生产的对象都在配置文件中给出定义,目的就是提高灵活性和可维护性。
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
控制反转(IoC/Inverse Of Control): 调用者不再创建被调用者的实例,由spring框架实现(容器创建)所以称为控制反转。
(对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。)
依赖注入(DI/Dependence injection) : 容器创建好实例后再注入调用者称为依赖注入。
我自己的理解:控制反转就是被控制的人的状态不是使用的人决定的,而是由一个第三方控制者决定的。而依赖注入则强调的是第三方控制者的决定方式是注入,所以叫做依赖注入,由百度的概念我们还知道另外一种方式是依赖查找。所以可以理解为控制反转的实现依赖的是注入或者是查找。
反射:不用new来创建对象,而是用类加载器,根据字符串名创建类,创建类的权利转移了,不是调用者new而是交给了IoC(inversion of control)控制容器来创建,是实现控制反转的关键技术。在java中,用Assembly.Load(集合名).CreateInstance(集合名.类名)来实现反射,对象是由IoC容器根据类加载器创建的。对象不是预先创建编译好,而是使用时动态创建。
控制反转:利用反射技术,将对象创建权利转移给容器,一般结合配置文件,读取根据配置文件创建对象,省去了用来判断创建哪个对象的switch和if语句。
依赖注入:依赖注入也是实现控制反转的一个技术,其实我们在项目中也经常用到,即对象的实例化由别的类注入,可以是容器创建了然后注入,也可以是另外的类中创建后注入,不是自己创建,也是将控制权转自给了别人。可以用构造函数也可以用set函数,如:
public class Logic{
myDataBase db;
public Logic(myDataBase mdb){
db = mdb;
}
或
public void setMyDatabase(myDataBase mdb){
db = mdb;
}
......
}
参数是实例化后的对象,不是自己new的,称为依赖注入。
资料来自于:
王二的DEMO理解
https://blog.csdn.net/qing_gee/article/details/98741476
【Spring】Spring的IOC(控制反转)/DI(依赖注入)原理(一):用到“反射”编程
https://blog.csdn.net/cangchen/article/details/44947947
对依赖注入,控制反转,反射的理解
https://blog.csdn.net/huierlc/article/details/51814714