转: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;
    }
}
 

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

GoF著作中未提到的设计模式(2):Interceptor的更多相关文章

  1. GOF---Java开发中的23种设计模式详解

    表点 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式 ...

  2. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  3. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  4. 0. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  5. JDK中所包含的设计模式

    本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图.首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助. 一.设计模式是什么(1)反复出现问题的解决方案( ...

  6. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  7. Java开发中的23种设计模式

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. [转载]java开发中的23种设计模式

    原文链接:http://blog.csdn.net/zhangerqing 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反 ...

  9. 【java】java开发中的23种设计模式详解

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

随机推荐

  1. Java刷题笔记

    能用StringBuffer的时候坚决不要用String,因为前者的时间和空间效率都更高. 牛顿法求平方根:随便找一个K,然后不断让 k=(k+x/k)/2;直到K的平方与x之间的差距小于限定值. 斐 ...

  2. pandas for python

    http://pandas.pydata.org/pandas-docs/stable/user_guide/index.html 不算太难,需要拿一本线性代数看看矩阵原理即可.重点在于考虑如何运用, ...

  3. PHP FILTER_SANITIZE_STRIPPED 过滤器

    定义和用法 FILTER_SANITIZE_STRIPPED 过滤器去除或编码不需要的字符. 该过滤器是 FILTER_SANITIZE_STRING 过滤器的别名 该过滤器删除那些对应用程序有潜在危 ...

  4. 【Dart学习】-- Dart之注释

    Dart支持三种注释类型: 单行注释,多行注释,文档注释. 单行注释单行注释以//开头,从//开始到一行结束的所有内容都会被Dart编译器忽略,示例代码如下: main(){ //打印输出 print ...

  5. 模拟+细节题——cf1236D

    思路好想,细节多的令人发指.. /* 反着判断:走完每个点=走过的路程=n*m-k 然后暴力判每行每列的目的地 每次走都能使走的范围缩小一行或者一列 */ #include<bits/stdc+ ...

  6. CSS:CSS 提示工具(Tooltip)

    ylbtech-CSS:CSS 提示工具(Tooltip) 1.返回顶部 1. CSS 提示工具(Tooltip) 本文我们为大家介绍如何使用 HTML 与 CSS 来创建提示工具. 提示工具在鼠标移 ...

  7. ES6十大特性(转载CSDN)

    1. const和let关键字 const用于定义常量. let用于定义变量.但是JavaScript中不是已经有变量了吗? 是的,这很正确,但用var声明的变量具有函数作用域,并会被提升到顶部. 这 ...

  8. 2 USB标准请求

    2 USB标准设备请求的结构 2.1 标准请求 bmRequestType 的D6~D5为00的请求,USB协议定义了11个标准请求(bRequest),其名字与相应的bRequest的值如下表: 表 ...

  9. 利用OpenFileDialog 获取图片存储到数据库中

    private void button1_Click(object sender, EventArgs e)        {            string fName;            ...

  10. keepalive基础知识

    一.LVS负载均衡集群的缺点 二.Keepalived介绍 三.Keepalived的功能 四.Keepalived工作原理 五.Keepalived组件框架 六.Keepalived的安装 6.1 ...