A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 僚机i 中级黑马   /  2014-3-30 14:21  /  1382 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

下面我们来看客户端:
Action action = (Action)ProxyAction.getInstance(new ViewAction());
Action.doAction();
    我们可以看到代理类对接口的依赖也转移到了客户端上,这样,代理类不依赖于某个接口。对于同样的代理类ProxyAction,我们也可以有如下的客户端调用:
Engine engine = (Engine)ProxyAction.getInstance(new EngineImpl());
Engine.execute();
    只要engineImpl类实现了Engine接口,就可以像上面那样使用。
    现在我们可以看到,动态代理的确是拥有相当的灵活性。但我们同时也看到了,这个代理类写起来比较麻烦,而且也差不多每次都写这样千篇一律的东西,只有委派前的动作和委派后的动作在不同的代理里有着不同,其他的东西都需要照写。如果这样的代理类写多了,也会有一些冗余代理。需要我们进一步优化,这里我们使用模板方法模式来对这个代理类进行优化,如下:
public abstract class BaseProxy implements InvocationHandler {
private Object obj;
protected BaseProxy(Object obj)
{
       this.obj = obj;
}
public static Object getInstance(Object obj,InvocationHandler instance)
{
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),instance);
}

public Object invoke(Object proxy, Method m, Object[] args)
               throws Throwable {
        // TODO Auto-generated method stub
        Object result;

       try {

           System.out.println("before method " + m.getName());
           this.doBegin();

           result = m.invoke(obj, args);

       } catch (InvocationTargetException e) {

           throw e.getTargetException();

       } catch (Exception e) {

           throw new RuntimeException("unexpected invocation exception: "

                  + e.getMessage());

       } finally {

           System.out.println("after method " + m.getName());
           this.doAfter();

       }

       return result;


}
public abstract void doBegin();
public abstract void doAfter();

}
    这样,代理的实现类只需要关注实现委派前的动作和委派后的动作就行,如下:
public class ProxyImpl extends BaseProxy {
protected ProxyImpl(Object o)
{
       super(o);
}
public static Object getInstance(Object foo)
{
        return getInstance(foo,new ProxyImpl(foo));
}

//委派前的动作
public void doBegin() {
        // TODO Auto-generated method stub
       System.out.println("begin doing....haha");

}

//委派后的动作
public void doAfter() {
        // TODO Auto-generated method stub
       System.out.println("after doing.....yeah");

}

}
    从上面的代码,我们可以看出代理实现类的确是简单多了,只关注了委派前和委派后的动作,这是我们作为一个代理真正需要关心的。
    至此,代理模式和动态代理已经告一段落。我们将动态代理引申一点说开去,来作为这篇文章的蛇足。
    这个话题就是面向方面的编程,或者说AOP。我们看上面的ProxyImpl类,它的两个方法doBegin()和doAfter(),这是做核心动作之前和之后的两个截取段。正是这两个截取段,却是我们AOP的基础。在OOP里,doBegin(),核心动作,doAfter()这三个动作在多个类里始终在一起,但他们所要完成的逻辑却是不同的,如doBegin()可能做的是权限,在所有的类里它都做权限;而在每个类里核心动作却各不相同;doAfter()可能做的是日志,在所有的类里它都做日志。正是因为在所有的类里,doBegin()或doAfter()都做的是同样的逻辑,因此我们需要将它们提取出来,单独分析、设计和编码,这就是我们的AOP的思想。
    这样说来,我们的动态代理就能作为实现AOP的基础了。好了,就说这么多,关于AOP技术,我们可以去关注关于这方面的知识。  


2 个回复

倒序浏览
值得学习ing!
回复 使用道具 举报
看看。。。。。。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马