zoukankan      html  css  js  c++  java
  • GoF著作中未提到的设计模式(2):Interceptor

    转:http://www.cnblogs.com/west-link/archive/2011/06/22/2086591.html

    拦截器模式为我们提供了一种拦截方法调用或消息的途径,整个过程是自动的、透明的,下面是一个简单的拦截器示意图:

     

      从图中可以看到,拦截器可以访问到方法调用的输入参数和返回结果,这样的话,拦截器能做的事儿就多啦,比如:   1、验证输入参数是否正确   2、偷偷地修改参数的值,例如参数类型的自动转换等   3、依赖注入   4、修改返回结果的内容、格式等

      下面是一个包含我们要拦截的方法的类:

    public class Action{
          // 拦截器集合的迭代器
          private Iterator interceptors;
          // 输入参数
          private Parameter param;
          // 返回结果
          private Result result;
          // 构造函数
          public Action(Parameter param);
          // 这个方法是我们要拦截的(具体实现见下面)
          public Result invoke();
          // 其他...
      }

    下面声明一个拦截器接口:

    public interface Interceptor{
      public Result intercept(Action action);
    }

    我们可能会想到以下的拦截方式:

    // 先在方法调用之前拦截一下,可以处理输入参数
    intercept(param);
    // 调用方法
    result = action.invoke(param);
    // 在方法调用之后再拦截一下,可以处理返回结果
    intercept(result);

    这种方式的缺点是不能完全地控制方法的调用,比如不能跳过方法的调用而直接返回结果、不能更改所在对象内部的状态等。

    下面的实现也能达到方法调用的前后拦截,并且有完全控制该对象的能力

    public Result invoke(){
      if( interceptors.hasNext() ){
        Interceptor interceptor = interceptors.next();
        result = interceptor.intercept(this);
      }
    }

    下面我们举几个拦截的具体例子:

    // 参数合法性验证拦截器
    public ParamInvalidator implements Interceptor{
        public Result intercept(Action action){
            Paramemter param = action.getParam();
            // 确保参数不为null
            if(param == null){
                addMessege("param is null!");
                // 创建一个默认的参数对象
                action.setParam(new Paramemter());
            }
            // 继续调用过程
            return action.invoke();
        }
    }
     

    一般来说,这类拦截器应该放在拦截器集合的最前面,所以,拦截器的被执行顺序是比较重要的!这依赖于具体的实现需求。

    如果需求有要求:参数为null时直接返回一个null的结果,停止调用过程,那么我们可以把上面的方法改成这样:

    public Result intercept(Action action){
        Paramemter param = action.getParam();
        if(param == null){
            return null;
        }
        // 继续调用过程
        return action.invoke();
    }
     

    所以,在所有的拦截器的实现中,action.invoke()这一行代码的位置或者有无非常重要,通过控制它我们就能在调用的前后进行拦截,甚至不调用它!

    public interface MoneyAware{
        public void setMoney(int money);
    }
    // 依赖注入拦截器
    public DependencyInjector implements Interceptor{
        public Result intercept(Action action){
            // 如果它实现了MoneyAware接口,那么我们就给它注入5毛钱
            if(action instanceof MoneyAware){
                action.setMoney(5);
            }
            // 继续调用过程
            return action.invoke();
        }
    }
     

    从这个拦截器可以看出,我们能修改被拦截对象的内部状态。

    // 结果格式化拦截器
    public ResultFormater implements Interceptor{
        public Result intercept(Action action){
            // 先调用要拦截的方法
            result = action.invoke();
            // 将结果格式化
            formatResult(result);
            // 返回结果
            return result;
        }
    }
     

    这个拦截器就是方法调用后的拦截,所以这种拦截器被执行的时候被放在调用堆栈的最下面,当其他拦截器执行完后,它才被执行!

  • 相关阅读:
    如何为创建大量实例节省内存?
    4-5
    4-6
    4-4
    4-3
    4-2
    3-11
    4-1
    3-10
    3-8
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/4700672.html
Copyright © 2011-2022 走看看