说实话,我对Spring技术还是不算很了解,IOC的技术我在实体框架技术中提到过,但IOC和AOP作为Spring技术的两个核心思想,我觉得在总结之前,还是有必要说明一下我所理解的IOC.
我们知道,如果两个事务之间存在逻辑关系,而且你需要根据这个逻辑关系做事,(比如类A和类B,类A需要调用类B的方法,比如ORM等),那么该做的事情,其实一件都不会少的,只是我们可以利用一些技术手段来减少直接的依赖或者叫硬代码依赖。IOC的核心其实就是利用辅助配置信息和编程语言提供的反射机制来替代这种硬关联,举个例子:
interface IB;
public class B1:IB;
public class B2:IB;
IB是一个接口,实现这个接口的类有2个:B1和B2,如果类A要调用这个接口,那么接口必须有一个实例来支持,我们看看几种用法:
为了说明简单,我们假设程序中只需要使用其中一个B类。
第1种方式(直接使用):
根据配置信息来创建B
IB theIB = new B1(),或者IB theIB = new B2(),
然后调用我们需要的方法,但这种方式有一个问题,就是判断使用B1还是B2的,以及实例化每次都要这么写,一是比较麻烦,二是没有收窄创建逻辑(如果创建逻辑发生变化,我们得到处改代码),因此我们做一个改进:
第2中方式(创建工厂):
public class CreateBfactory
{
public IB CreateInstanceForB()
{
在这里根据配置信息来创建B
IB theIB = new B1(),或者IB theIB = new B2(),
返回实例theIB
}
}
第2中方式,对于一般的情况应该是够用了,但有的时候,创建逻辑比较简单,或者是不想要这个创建逻辑,而是在程序配置文件中直接指明用什么,这就是第3中方式。
第3种方式(配置):
这里假设配置格式是:<interface="IB" usingclass="B1" assembly=""....>
一般的情况下,我们要创建一个类实例,是必须知道类类型的,我们在代码中无法直接用类名字符串来创建实例的,但由于很多语言都支持根据元数据,并根据元数据动态创建实例,那么我们当然就可以利用这种配置信息来创建类实例。在C#中的代码其实很简单:
string theTypeName = "完全类名,程序集名";//完全类名包括了命名空间的完整类型名,注意大小写,程序集名则是要实例化类所在的程序集,如果在当前加载的程序集中,可以不写。
Type theTargetType = Type.GetType(theTypeName );
然后调用Activtor.CreateInstanceFrom(theTargetType )就可以动态构建。
如果系统中存在着大量这样的类需要创建,而且创建逻辑简单,那么采用这种方式有如下好处:
1)只要写一个根据配置文件创建目标实例的工厂类,大大减少了代码;
2)如果要将B1换到B2,我们只需要改配置文件,而不需要修改程序,当然也就不需要重新编译程序了
3)为按需加载程序集,动态加载程序集提供了可能。
第3种方式其实就是典型的IOC.至于配置信息是放在数据库还是文件里,存什么格式都可以根据自己的需要来决定,甚至可以根据命名规范来进行(比如我的数据访问类根据数据库类型的不同分为不同的版本类,我就直接利用命名规范来实现配置,比如接口I_Name,Oracle版:C_Name_O,因为程序集是肯定会加载的,我就可以根据I_Name的类型名加上采用哪个数据库的配置信息就可以轻松创建需要的实例)。当然,根据配置文件我们还可以完成很多更为复杂的事情,但原理是一样的。
IOC:配置信息+类的动态实例化技术。
不过这种技术并不适合创建逻辑复杂的地方,一是因为如果配置文件过于复杂,本身也难以维护,二是配置文件所能表达的逻辑也有限。IOC特别适合创建逻辑简单,配置信息形式统一,但量比较大的地方。