IOC
一个大型项目需要依托于对象间的依赖关系,如果这些依赖关系通过对象自身去管理的话,那么耦合度将会很高,不易于系统的扩展和维护。这时我们可以将对象的创建、依赖关系的管理以及生命周期交由IOC容器来管理,而对象只需要专心负责承载和处理数据即可。这样的设计可以降低系统在实现上的复杂性和耦合度,易于扩展,满足开闭原则。
依赖注入 DI
含义:把底层类作为参数传递给上层类,实现上层对下层的控制
用依赖注入DI实现控制反转
以设计行李箱为例子
我们传统的设计理念是,先设计出轮子,根据轮子设计出底盘,根据底盘设计出箱体,根据箱体设计出行李箱
如果现在出现了一个变动,需要修改轮子的尺寸,那么底盘的尺寸也得改,箱体的尺寸也得改,行李箱的尺寸也得改。
如果我们想要将轮胎的尺寸改成动态的,那么我们就需要如下修改代码
在大型的软件工程中,有的类甚至是几千个类的基层,那么如果要修改这个类,则需要修改几千个类的代码
这时我们就可以使用依赖注入DI实现控制反转
我们换种实现方式,这样子依赖关系就倒置过来了,轮子依赖于底盘,底盘依赖于箱体,箱体依赖于行李箱。这时如果想要改动轮子的设计,就只需要改动轮子即可。
依赖注入的三种实现方式:1.构造函数传入方式 2.set方法传递注入 3.接口注入
使用构造函数传入方式改造上面的代码
这时如果要修改轮胎尺寸为动态的,只需要修改轮胎类的代码
IOC/DI/DL的关系
IOC可以通过DL或者DI实现。DI是当今主流的IOC实现方式
依赖倒置原则、IOC、DI、IOC容器的关系
依赖倒置原则指的是下层依赖于上层。根据依赖倒置原则产生了一个编程思路-控制反转IOC。IOC可以通过依赖注入DI来实现。Spring等框架通过IOC编程思路实现了IOC容器。对于IOC来说,容器是最重要的。容器管理着Bean的生命周期,控制着Bean的依赖注入。
下面这部分就是由我们的IOC容器来实现的:
IOC容器的优势
1.IOC容器自动对代码进行初始化,避免在各处使用new来创建类,并且可以做到统一维护。只需要用户维护一个配置文件或者注解,而不用每一次初始化一个类,就写一大段创建对象的语句。
2.创建实例的时候不需要了解其中的细节。
3.反射+工厂模式的合体,满足开闭原则。IOC中最基本的技术就是反射,根据给出的类名来动态的生成对象,这种编程方式可以让对象在生成时被决定到底是哪一种对象。在配置文件中给出工厂要生产的对象的定义,利用反射机制根据配置文件中给出的类名生成相应的对象。
拿上面的例子来看,用户端只需要向IOC容器请求创建行李箱实例,IOC容器会返回一个建立好的行李箱实例,用户不需要关注行李箱实例的创建细节。
IOC容器根据用户的需求去配置文件中查询实例的依赖,从最底层的实例开始创建,将底层实例一步步往上层实例中注入。
Spring实现IOC
Spring容器会根据配置文件来创建对象,同时将其依赖的对象通过构造函数或set方法的形式注入到对象中。
1.创建SpringConfig.xml的文件
<beans> <bean id=”sale” class=”Sale” singleton=”false”> <constrctor-arg> <ref baen=”tea”> </constrctor-arg> </bean> <bean id=”tea” class=”BlueTea” singleton=”false”> </beans> |
2.实现类
class Sale{ Private AbstractTea t; Public Sale(AbstractTea t){ This.t=t; } } |
当要将注入对象改成BlackTea类时,就直接更改配置文件就可以
3.获取对象
ApplicationContext xtx= new FileSystemXmlApplicationContext(“SpringConfig.xml”); Sale s=(Sale) ctx.getBean(“sale”); |