Spring 依赖注入(控制反转)介绍
2013-10-27 01:27
459 查看
耦合性是软件工程中的一个重要概念。对象之间的耦合性就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。 spring Ioc思想 控制翻转也就是spring所推出的依赖注入
传统的方法假设我们前端用的struts,那么action中我们对业务逻辑的编写一般是这样的
这里是一段伪代码:
publicclass CustomerDao { publicboolean getCustomerByAccount() {/* 代码 */ } }
publicclass LoginAction { publicvoid execute() { CustomerDao cdao =new CustomerDao(); boolean b = cdao.getCustomerByAccount(); // 判断 } }
在LoginAction中,execute内直接实例化了CustomerDao对象,此时,相当于让LoginAction的使用依赖了 CustomerDao,换句话说,如果没有CustomerDao类,LoginAction将无法被编译、测试。另外,如果CustomerDao类 换成另一版本,比如原先的CustomerDao,是访问SQLServer数据库,后面我们又另外编写了CustomerDao2类,访问Oracle 数据库,那么需要将LoginAction内所有出现CustomerDao的地方改为CustomerDao2。非常麻烦。这就是耦合性高的代价。
那么如何降低耦合性呢,我们可以将变化较大的类改成变化较小的接口,然后在action中通过一个工厂类来返回相应的对象。将代码修改为:
publicinterface ICustomerDao { publicboolean getCustomerByAccount(); }
publicclass CustomerDao implements ICustomerDao { publicboolean getCustomerByAccount(){/* 代码 */ } } //工厂类publicclass DaoFactory { publicstatic ICustomerDao getCustomerDao() { returnnew CustomerDao(); } }
publicclass LoginAction { publicvoid execute() { ICustomerDao icdao = DaoFactory.getCustomerDao(); boolean b = icdao.getCustomerByAccount(); // 判断 } }
在上面的程序中,如果需要做CustomerDao的切换,如,从CustomerDao改为CustomerDao2,就只需让CustomerDao2实现"ICustomerDao"接口,然后修改工厂的方法,而不用修改LoginAction内的代码。
LoginAction只需要认识ICustomerDao接口,不需要认识具体的实现类。而接口修改的概率比实现类要低得多。因此,这样编写就降低了程序的耦合性,是一个比较好的方法。
但是,以上方法也不是没有修改的余地。当Dao进行切换时,还是需要修改BeanFactory的源代码,能否避免这个问题呢?可以对DaoFactory进行改进,使得它能为所有类服务。代码如下
publicinterface ICustomerDao { publicboolean getCustomerByAccount(); }
publicclass CustomerDao implements ICustomerDao { publicboolean getCustomerByAccount() {/* 代码 */ } }
publicclass BeanFactory { publicstatic Object getBean(String className) { return Class.forName(className).newInstance(); } }
publicclass LoginAction { publicvoid execute() { ICustomerDao icdao = (ICustomerDao)BeanFactory.getBean("CustomerDao"); boolean b = icdao.getCustomerByAccount(); // 判断 } }
此处使用了反射机制。修改后,需要切换的时候只需在LoginAction内改变类名,工厂内就会自动生成对象返回给LoginAction。在 LoginAction中,由于类名是字符串,因此,就可以将该字符串写在一个配置文件内,让LoginAction读入,这样,当 CustomerDao类名需要切换时,就直接修改配置文件就行了。不用改源代码,模块之间的耦合就完全由配置文件决定。
这种设计方法有一个好处是,BeanFactory类的通用性很强,就可以将其框架化。因此,框架化之后,对象的生成由框架参考配置文件进行,和具 体实现类的源代码无关,将对象生成的控制权由修改不方便的源代码转变为修改相对方便的配置文件与几乎不进行修改的框架进行,这就是控制反转 (Inverse Of Control,IOC)的原理。
传统的方法假设我们前端用的struts,那么action中我们对业务逻辑的编写一般是这样的
这里是一段伪代码:
publicclass CustomerDao { publicboolean getCustomerByAccount() {/* 代码 */ } }
publicclass LoginAction { publicvoid execute() { CustomerDao cdao =new CustomerDao(); boolean b = cdao.getCustomerByAccount(); // 判断 } }
在LoginAction中,execute内直接实例化了CustomerDao对象,此时,相当于让LoginAction的使用依赖了 CustomerDao,换句话说,如果没有CustomerDao类,LoginAction将无法被编译、测试。另外,如果CustomerDao类 换成另一版本,比如原先的CustomerDao,是访问SQLServer数据库,后面我们又另外编写了CustomerDao2类,访问Oracle 数据库,那么需要将LoginAction内所有出现CustomerDao的地方改为CustomerDao2。非常麻烦。这就是耦合性高的代价。
那么如何降低耦合性呢,我们可以将变化较大的类改成变化较小的接口,然后在action中通过一个工厂类来返回相应的对象。将代码修改为:
publicinterface ICustomerDao { publicboolean getCustomerByAccount(); }
publicclass CustomerDao implements ICustomerDao { publicboolean getCustomerByAccount(){/* 代码 */ } } //工厂类publicclass DaoFactory { publicstatic ICustomerDao getCustomerDao() { returnnew CustomerDao(); } }
publicclass LoginAction { publicvoid execute() { ICustomerDao icdao = DaoFactory.getCustomerDao(); boolean b = icdao.getCustomerByAccount(); // 判断 } }
在上面的程序中,如果需要做CustomerDao的切换,如,从CustomerDao改为CustomerDao2,就只需让CustomerDao2实现"ICustomerDao"接口,然后修改工厂的方法,而不用修改LoginAction内的代码。
LoginAction只需要认识ICustomerDao接口,不需要认识具体的实现类。而接口修改的概率比实现类要低得多。因此,这样编写就降低了程序的耦合性,是一个比较好的方法。
但是,以上方法也不是没有修改的余地。当Dao进行切换时,还是需要修改BeanFactory的源代码,能否避免这个问题呢?可以对DaoFactory进行改进,使得它能为所有类服务。代码如下
publicinterface ICustomerDao { publicboolean getCustomerByAccount(); }
publicclass CustomerDao implements ICustomerDao { publicboolean getCustomerByAccount() {/* 代码 */ } }
publicclass BeanFactory { publicstatic Object getBean(String className) { return Class.forName(className).newInstance(); } }
publicclass LoginAction { publicvoid execute() { ICustomerDao icdao = (ICustomerDao)BeanFactory.getBean("CustomerDao"); boolean b = icdao.getCustomerByAccount(); // 判断 } }
此处使用了反射机制。修改后,需要切换的时候只需在LoginAction内改变类名,工厂内就会自动生成对象返回给LoginAction。在 LoginAction中,由于类名是字符串,因此,就可以将该字符串写在一个配置文件内,让LoginAction读入,这样,当 CustomerDao类名需要切换时,就直接修改配置文件就行了。不用改源代码,模块之间的耦合就完全由配置文件决定。
这种设计方法有一个好处是,BeanFactory类的通用性很强,就可以将其框架化。因此,框架化之后,对象的生成由框架参考配置文件进行,和具 体实现类的源代码无关,将对象生成的控制权由修改不方便的源代码转变为修改相对方便的配置文件与几乎不进行修改的框架进行,这就是控制反转 (Inverse Of Control,IOC)的原理。
相关文章推荐
- spring的容器(控制反转、依赖注入)
- Spring 使用注解的方式实现IOC和DI(控制反转和依赖注入)
- Spring源码阅读——简单模拟Spring的控制反转IOC和依赖注入(Bean的加载和获取)
- Spring的IOC(控制反转)和 DI(依赖注入)机制
- Spring.net step by step——依赖注入(DI)和控制反转(IOC)
- 如何理解spring中的IOC(控制反转)、DI(依赖注入)?
- Spring学习3—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)
- 【Spring】Spring的IOC(控制反转)/DI(依赖注入)原理(一):用到“反射”编程
- Spring_控制反转(IOC)/依赖注入(DI)
- spring控制反转和依赖注入(第一个spring程序)
- Spring基础学习(二)——IOC(控制反转)介绍
- 切面(aop)控制反转和依赖注入(IOC,DI)和spring的事务隔离和传播行为
- Spring-IOC(控制反转)+DI(依赖注入)
- Spring学习—控制反转(IOC)Spring依赖注入(DI)和控制反转(IOC)
- Spring 深入理解IOC(控制反转)和DI(依赖注入)
- Spring IoC(控制反转)和DI(依赖注入)的理解
- Spring、控制反转与依赖注入(概念)
- spring IOC(控制反转)和DI(依赖注入)以及三种依赖注入方式的比较
- Spring、控制反转与依赖注入(概念)
- 【转】跟我一起学Spring 3(4)–深入理解IoC(控制反转)和DI(依赖注入)