IoC 就是 控制反转的意思
要了解 IoC 就需要先对设计模式有些了解
呵呵 设计模式讲究的一点 就是“先接口(稳定)后实现(善变)”
稳定住稳定的部分,也就是接口,变化善变的部分,也就是实现接口的类。
举个例子吧,假如 Invoker 类包含一个字段为 ChildA a,ChildA 类包含着 CallMe() 方法
那么在Invoker内部,任何一个调用 a.CallMe() 的方法都是在直接调用(控制)着 ChildA 类。这就叫“主动控制”——调用谁的决 定 权在 Invoker。
因为Invoker直接依赖于ChildA类,而假如有个ChildB类提供相同的方法 CallMe(),但其方法内部实现不同,那么要换掉ChildB类的 话,则需要将Invoker类的字段a的声明 ChildA 改为 ChildB...这在设计模式中是不合适的。
设计模式中的做法呢,就是把ChildA ChildB ChildC... 抽象成一个接口,即IChild,同样由Invoker调用方法CallMe()。但此时Invoker 的依赖就变了...它依赖的是接口!控制由典型的 实现-实现 变成了实现-接口(或者可以 接口-接口——只需把Invoker类抽象成 IInvoker接口即可)。这就叫“反转控制”——调用谁的决定权在 IChild(是啊,由它来决定到底该调用ChildA 还是 ChildB)
这就出来一个问题了,谁来作Invoker.a?是ChildA?ChildB?还是其他集成自IChild的类?这就是IoC要考虑的问题了~~
我最喜欢IoC的地方就是它可以把由代码实现的部分转换成XML文件
上例说Invoker.a字段的实例类型该由谁来决定,IoC就可以做到
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/applicationContext.xml");
Invoker.a = (IChild)ctx.getBean("ChildA");
com/applicationContext.xml 的内容包括使用 ChildA 和 ChildB 的方法,代码"ChildA"来充当 Invoker.a 的实例。
别看在这个例子中,IoC的运用还不够实际,但在真正的编程中,你会从这里感觉到很多便利之处(如插件编程即是一例)
然后就是AOP了。AOP就是面向切面(横向)编程。一般程序都是按流程来执行(如IF,循环等),这属于纵向编程。那么横向编程呢,指的就是流程外的部分,如“日志”、“持久化”、“事务”等等方面的。
就拿日志举例吧。用过C++的都明白,每个函数都应该用到形如LOG这样的宏来作日志操作。尤其是函数的进入和退出,这其中还要有函数的执行时间计算等等操作,假如统统写到每个函数中去,不仅会造成代码冗余~而且万一要是有一个函数忘了写这些重复的代码的话...
我觉得AOP的本质无非就是消除多余代码,并让程序设计人员把更多的时间和精力关注到代码逻辑,而不是投入到像“日志”、“持久化”这样重复、枯燥、易生漏洞又不易管理(想想每个函数都要有相同的日志代码...)的代码上,那会是多爽的事!AOP就是用以解决这类问题的(至少我在C#中是这样)。
既然IoC可以通过XML来决定代码的依赖性,那么AOP(Spring)则通过XML文件来定位这些切面点(也就是“日志”、“持久化”啊之类的,都可以看成是一个个切面点,也就是横向点)。通过代理类充当实现这些切面点的模板。例如我可以搞出个代理类来专门用于日志操作,只要实现 AOP 中的MethodInterceptor 和 Serializable 接口,我们就可以编写属于自己的函数日志模板,接口中有一个方法,即Object invoke(MethodInvocation invocation) 。嘿嘿,有了它,你就可以通过invocation字段(即通过 MethodInvocation 类中的实例方法)中的process方法,可以执行这个通过XML代入的函数;当然也可以访问Logger等类,对这个方法进行日志等操作,想干什么就干什么。
这就相当于一个模板,你要记录什么函数,只需将这个方法代入 invoke方法中的 invocation 形参内即可~例如你要把软件内所有函数方法都放进去,那只需更改XML文件,那么当程序运行的时候,这些个函数就无一例外的执行invoke操作——也就是记录日志。想去掉某个函数的日志操作,只需在XML文件中去掉它即可。再也不必在每个函数中写那些日志代码了。
那么方法又是怎么当作参数放进invoke内呢?这就需要XML文件了。呵呵关于XML的内容实在太多(跟个类库似的,需要查资料,我懒得查了嘿嘿),我就不写了。
AOP这么做的优点自不必多说,相信前面那么多废话,你也能看出些来了。就日志而言(何况远不止日志这一个切面这么简单,比如“持久化”等),有了它,程序员只需关注函数逻辑层面,而不必过于关注日志方面的内容即可。这样我们再也不必到每个函数里写那些形如 LOG_START LOG_END,然后再用时间差...这样的东西了,把这一切都交给代理类,剩下的,则是实现与你函数名相关的功能即可。
如果还不太...可以举个超简单的伪代码例子(形如C):
未用AOP的这段代码
public int Add(int a, int b) {
int result;
LOG_START;
result = a + b;
LOG_END;
return result;
}
用过AOP后的这段代码:
public int Add(int a, int b) {
return a + b;
}
把该函数放入XML文件,通过AOP类(如Spring中的)来实现日志记录(如读取这个XML文件等)这样的代理类,最终程序运行时,会自动将这个函数日志化。
我只是把这些思想给你,因为本人喜欢C#编程(相比较而言,C#在AOP的实现中,除了XML外还有一个选择,那就是 Attribute,这也是我比较喜欢的东西,虽然它不简单),对Spring这种Java实现……呵呵,很抱歉不能提供更多的代码给你。不过思想是相通的,一通百通,相信你能在这些话中,体会到IoC和AOP的一点本质~这样纵然你到C中去,也有可能实现这些(虽然在C中至今还没有像Spring那样的类库^_^)。一通百通嘛
AOP对性能会造成不小的影响(反射等造成的)。因此企业运用或许合适,但桌面型运用可就要慎重了!!!一般我是不过于用它,我宁可多写些代码~~(C++的AOP例外,它是编译器级别的,虽很麻烦,但结果却丝毫不影响性能!具体不介绍了,C++ AOP和JAVA AOP完全不一样,但本质,也就是我刚才说的那些东西,是一致的!)
要了解 IoC 就需要先对设计模式有些了解
呵呵 设计模式讲究的一点 就是“先接口(稳定)后实现(善变)”
稳定住稳定的部分,也就是接口,变化善变的部分,也就是实现接口的类。
举个例子吧,假如 Invoker 类包含一个字段为 ChildA a,ChildA 类包含着 CallMe() 方法
那么在Invoker内部,任何一个调用 a.CallMe() 的方法都是在直接调用(控制)着 ChildA 类。这就叫“主动控制”——调用谁的决 定 权在 Invoker。
因为Invoker直接依赖于ChildA类,而假如有个ChildB类提供相同的方法 CallMe(),但其方法内部实现不同,那么要换掉ChildB类的 话,则需要将Invoker类的字段a的声明 ChildA 改为 ChildB...这在设计模式中是不合适的。
设计模式中的做法呢,就是把ChildA ChildB ChildC... 抽象成一个接口,即IChild,同样由Invoker调用方法CallMe()。但此时Invoker 的依赖就变了...它依赖的是接口!控制由典型的 实现-实现 变成了实现-接口(或者可以 接口-接口——只需把Invoker类抽象成 IInvoker接口即可)。这就叫“反转控制”——调用谁的决定权在 IChild(是啊,由它来决定到底该调用ChildA 还是 ChildB)
这就出来一个问题了,谁来作Invoker.a?是ChildA?ChildB?还是其他集成自IChild的类?这就是IoC要考虑的问题了~~
我最喜欢IoC的地方就是它可以把由代码实现的部分转换成XML文件
上例说Invoker.a字段的实例类型该由谁来决定,IoC就可以做到
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/applicationContext.xml");
Invoker.a = (IChild)ctx.getBean("ChildA");
com/applicationContext.xml 的内容包括使用 ChildA 和 ChildB 的方法,代码"ChildA"来充当 Invoker.a 的实例。
别看在这个例子中,IoC的运用还不够实际,但在真正的编程中,你会从这里感觉到很多便利之处(如插件编程即是一例)
然后就是AOP了。AOP就是面向切面(横向)编程。一般程序都是按流程来执行(如IF,循环等),这属于纵向编程。那么横向编程呢,指的就是流程外的部分,如“日志”、“持久化”、“事务”等等方面的。
就拿日志举例吧。用过C++的都明白,每个函数都应该用到形如LOG这样的宏来作日志操作。尤其是函数的进入和退出,这其中还要有函数的执行时间计算等等操作,假如统统写到每个函数中去,不仅会造成代码冗余~而且万一要是有一个函数忘了写这些重复的代码的话...
我觉得AOP的本质无非就是消除多余代码,并让程序设计人员把更多的时间和精力关注到代码逻辑,而不是投入到像“日志”、“持久化”这样重复、枯燥、易生漏洞又不易管理(想想每个函数都要有相同的日志代码...)的代码上,那会是多爽的事!AOP就是用以解决这类问题的(至少我在C#中是这样)。
既然IoC可以通过XML来决定代码的依赖性,那么AOP(Spring)则通过XML文件来定位这些切面点(也就是“日志”、“持久化”啊之类的,都可以看成是一个个切面点,也就是横向点)。通过代理类充当实现这些切面点的模板。例如我可以搞出个代理类来专门用于日志操作,只要实现 AOP 中的MethodInterceptor 和 Serializable 接口,我们就可以编写属于自己的函数日志模板,接口中有一个方法,即Object invoke(MethodInvocation invocation) 。嘿嘿,有了它,你就可以通过invocation字段(即通过 MethodInvocation 类中的实例方法)中的process方法,可以执行这个通过XML代入的函数;当然也可以访问Logger等类,对这个方法进行日志等操作,想干什么就干什么。
这就相当于一个模板,你要记录什么函数,只需将这个方法代入 invoke方法中的 invocation 形参内即可~例如你要把软件内所有函数方法都放进去,那只需更改XML文件,那么当程序运行的时候,这些个函数就无一例外的执行invoke操作——也就是记录日志。想去掉某个函数的日志操作,只需在XML文件中去掉它即可。再也不必在每个函数中写那些日志代码了。
那么方法又是怎么当作参数放进invoke内呢?这就需要XML文件了。呵呵关于XML的内容实在太多(跟个类库似的,需要查资料,我懒得查了嘿嘿),我就不写了。
AOP这么做的优点自不必多说,相信前面那么多废话,你也能看出些来了。就日志而言(何况远不止日志这一个切面这么简单,比如“持久化”等),有了它,程序员只需关注函数逻辑层面,而不必过于关注日志方面的内容即可。这样我们再也不必到每个函数里写那些形如 LOG_START LOG_END,然后再用时间差...这样的东西了,把这一切都交给代理类,剩下的,则是实现与你函数名相关的功能即可。
如果还不太...可以举个超简单的伪代码例子(形如C):
未用AOP的这段代码
public int Add(int a, int b) {
int result;
LOG_START;
result = a + b;
LOG_END;
return result;
}
用过AOP后的这段代码:
public int Add(int a, int b) {
return a + b;
}
把该函数放入XML文件,通过AOP类(如Spring中的)来实现日志记录(如读取这个XML文件等)这样的代理类,最终程序运行时,会自动将这个函数日志化。
我只是把这些思想给你,因为本人喜欢C#编程(相比较而言,C#在AOP的实现中,除了XML外还有一个选择,那就是 Attribute,这也是我比较喜欢的东西,虽然它不简单),对Spring这种Java实现……呵呵,很抱歉不能提供更多的代码给你。不过思想是相通的,一通百通,相信你能在这些话中,体会到IoC和AOP的一点本质~这样纵然你到C中去,也有可能实现这些(虽然在C中至今还没有像Spring那样的类库^_^)。一通百通嘛
AOP对性能会造成不小的影响(反射等造成的)。因此企业运用或许合适,但桌面型运用可就要慎重了!!!一般我是不过于用它,我宁可多写些代码~~(C++的AOP例外,它是编译器级别的,虽很麻烦,但结果却丝毫不影响性能!具体不介绍了,C++ AOP和JAVA AOP完全不一样,但本质,也就是我刚才说的那些东西,是一致的!)
总的来说 IoC和AOP形如两种技术,但他们之间还是有不小的联系。
转自:http://blog.csdn.net/mingwar/article/details/4955422