GoF著作中未提到的设计模式之二:Interceptor

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

 

  从图中可以看到,拦截器可以访问到方法调用的输入参数和返回结果,这样的话,拦截器能做的事儿就多啦,比如:
  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; } }
复制代码

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值