IOC与AOP的本质

IOC

1 问题引出

在软件开发过程中,依赖是无法避免的。以桥接模式举例,如下图。
在这里插入图片描述
Face模块要使用Executor模式,从设计上是希望Face直接使用抽象的Exector,即AbstractExecutor。但是在实际的过程中我们需要先构造AbstractExecutor的实例的时候,不得不去new ExecutorImpl。假设该类在代码中被广泛使用,那么就会在很多地方出现new ExecutorImpl这样的代码,一旦我们扩展了一个新的类ExecutorImplTwo,那么就不得不修改这些new ExecutorImpl的代码。这样严重违反了开闭原则
为了解决这个问题,出现了工厂模式。用工厂模式去包装new ExecutorImpl的过程。当出现需要将new ExecutorImpl改为new ExecutorImplTwo的时候,只需要改工厂类中的实现。这样一定程度地解决了问题。但是仍然美中不足

  • 虽然在一定程度降低了当ExecutorImpl改变的时候需要修改构造的代码行数,但是,还是没有做到绝对不修改。也就是说没有严格开闭
  • 当Executor的实现类的构造参数不一致的情况,这时的工厂方法就未必管用。这时,有人说用抽象工厂吧,遗憾的是:你把问题抛给了抽象工厂,抽象工厂的构建过程和构建接口参数也会面临同样的问题。所以你只是把问题帅锅给了抽象工厂而已,并没有根本解决问题。

2 解决问题

要做到解决上面的问题,即要实现控制反转(即IOC),它是面向对象的一个设计原则。最常见的实现方式就是依赖注入(即DI)。其中最有名的就是spring的依赖注入特性,它是借助java语言的反射特性为基础,实现的一个强大的依赖注入框架,当然依赖注入只是它强大特性的一个点。对于c++语言而言,没有反射,可以借助模板实现类似反射功能。

AOP

1 问题引出

在开发中,我们经常需要在一个函数的调用前或后添加一些补充功能,例如加入日志打印、拦截过滤。这个时候,利用模板模式装饰器模式可以实现类似功能。
模板方法如下:
模板方法
装饰模式如下:
装饰模式
无论是模板方法还是装饰模式,都要求实现者要按照固定的套路去编写代码。如果我们调用的代码是第三个已经写好的代码,并不会按照我们预想的方法去实现,那么模板方法和装饰模式就不灵了。有人会说我们可以通过外观模式去包装,但是如果我们只需要添加一行日志,就要去动员大量代码包装的成本也不现实;此外,如果在人家已经写好的代码的调用流程中无缝添加功能,这时传统的模式都无法做到不修改既有代码而做到功能的无缝插入

2 解决问题

为了解决前面的问题,一种编程思想AOP(Aspect Oriented Program)被提出,即面向切面编程。在java强大的动态代理机制下,为AOP提供了技术实现可行性。当然,c++利用模板也可以做到粗暴的AOP方式,但是对于调用者还是有感知的。spring库的AOP使用如下:

  • 定义接口
public interface HelloWorld
{
    
    
    void print();
}
  • 实现接口
public class HelloWorldImpl implements HelloWorld
{
    
    
    public void print()
    {
    
    
        System.out.println("Enter HelloWorldImpl.print()");
    }
}
  • 实现切面
public class TestHandler
{
    
    
    public void test()
    {
    
    
        System.out.println("TestHandler Interceptor");
    }
}
  • spring配置文件 aoptest.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"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="HelloWorldImpl" class="com.example.aop.HelloWorldImpl" />
        <bean id="TestHandler" class="com.example.aop.TestHandler" />
        
        <aop:config>
            <aop:aspect id="cutin" ref="TestHandler">
                <aop:pointcut id="allMethod" expression="execution(*com.example.aop.HelloWorld.*(..))" />
                <aop:before method="test" pointcut-ref="allMethod" />
                <aop:after method="test" pointcut-ref="allMethod" />
            </aop:aspect>
        </aop:config>
</beans>
  • 使用AOP
public static void main(String[] args)
{
    
    
    ApplicationContext ctx = 
            new ClassPathXmlApplicationContext("aoptest.xml");
        
    HelloWorld hw = (HelloWorld)ctx.getBean("HelloWorldImpl");
    hw.print(); 
}
  • 测试输出如下
TestHandler Interceptor
Enter HelloWorldImpl.print()
TestHandler Interceptor

总结

无论是IOC还是AOP,它的出现都不是为了技术新意而新意。任何很牛逼的技术都是以解决实际业务目标为第一要务。他们的直接目标是为了解除耦合,使之严格符合开闭原则;根本目标是为了便于开发协作,即隔离依赖、并行开发

猜你喜欢

转载自blog.csdn.net/fs3296/article/details/103738202