转: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. vmware下搭建openwrt

    最近闲来无事,想研究下openwrt, 所以尝试着自己搭建一个来玩玩, 当然这里不是以源码编译的形式,那样太耗时. 首先官网下载已有的系统image,  路径如下 : https://archive. ...

  2. 概率——17icpc西安

    不知道为什么是这样子的.. #include<bits/stdc++.h> using namespace std; int m,n; int main(){ while(scanf(&q ...

  3. Java桌球小游戏

    版本一.出现窗口package cn.xjion.game;/** * 出现窗口 * @author xjion * */import java.awt.*;import javax.swing.*; ...

  4. sublime text3配置c++环境和一些插件

    目录 Sublime Text 3是一个轻量级文本编辑器 下载sublime text 3: 安装MinGW 配置环境变量 win下行编译运行C/C++文件 Build你的C++System~ 快捷键 ...

  5. php开发面试题---2、php常用面试题二(表单提交方式中的get和post有什么区别)

    php开发面试题---2.php常用面试题二(表单提交方式中的get和post有什么区别) 一.总结 一句话总结: 数据位置:get参数在url里面,post在主体里面 数据大小:get几kb,pos ...

  6. JS互相调用

    JS互相调用 例1: <html> <head> <meta charset="UTF-8"> <script type="te ...

  7. Codeforces 1176B - Merge it!

    题目链接:http://codeforces.com/problemset/problem/1176/B 题意:给定序列,任意俩个元素可以相加成一个元素,求序列元素能被3整除的最大数量. 思路: 对于 ...

  8. 面向对象(三)——组合、多态、封装、property装饰器

    组合.多态.封装.property装饰器 一.组合 1.什么是组合 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象 class Foo(): pass class Bar(): pas ...

  9. 实用的CSS3-渐变背景色

    线性渐变背景色:     第一个参数为渐变方式,后两个参数为起始点位置和终止点位置,后两个参数为起始颜色和终止颜色,后面那个参数为背景区域padding表示包含padding的区域,content表示 ...

  10. 调用API接口,查询手机号码归属地(1)

    使用https://www.juhe.cn/提供的接口,查询归属地 在官网注册key即可使用. 代码如下 #!/usr/bin/python # -*- coding: utf-8 -*- impor ...