巧用拦截器:高效的扩展点设计

最近在设计框架时,需要设计一类扩展点,发现不能简单地继承或使用事件来给使用者提供 API。最终使用拦截器模式解决了 API 的设计。

 

扩展点使用场景


该扩展点的使用场景如下:

  1. 不能使用继承;需要在类型的继承体系外(非被扩展类型的子类)对类型进行扩展。
  2. 需要能在基本逻辑的执行前、后扩展新的逻辑,甚至可以使用新的逻辑替换基础逻辑。
  3. 对于性能敏感。由于该基础逻辑是比较核心的代码,需要尽量地减少扩展点带来的额外性能消耗、并尽量少地产生额外的对象。

 

扩展点设计方案选型


在框架设计时,扩展点设计主要通过几种类型的 API 来提供:虚方法、事件、接口。(关于扩展点的设计,详细的内容,参见:《Framework Design Guidelines 2nd Edition》第六章,扩展性设计。)而最常用、最方便使用者使用的扩展点则是前两个:虚方法和事件。

前两种扩展点设计方案的主要区别在于:

  1. 场景:继承中的虚方法主要是为类型的子类型进行扩展而提供的,而事件则主要是为继承体系外的类型来扩展继承体系内的类型的行为而提供的;
  2. 控制度:子类对虚方法进行重写时,可以在基类的基本方法前、后编写自己的扩展代码,同时还可以控制是否需要调用基类的方法;而事件要实现这些功能,需要提供逻辑前事件(Invoking)、逻辑后事件(Invoked),并通过类似 CancelEventArgs.IsCancel 属性等方式来控制是否需要执行基本的逻辑。
  3. 性能:虚方法的调用是非常高效的,也不会产生额外的对象。而事件的机制本质是委托列表,会遍历该列表进行调用,同时需要产生额外的委托对象;其次,由于 .NET 事件的设计中往往要求提供一个从 EventArgs 类型上继承的事件参数对象,在每次调用都构造并传递该对象,这也会产品额外的对象压力。

可以看出,如果是想设计一类提供给继承体系外类型进行扩展的扩展点, 虚方法、事件两类 API 都不合适。那我们只能在第三种方式上想办法:接口。接口的设计则非常灵活,而其实我上面描述的场景会经常遇到,所以应该提取出一类设计模式。经过一番思考,我发现其实拦截器模式比较适合该场景。拦截器模式本身注重对消息、方法的拦截处理,是一种继承体系外的扩展方法,并被大量用于 AOP 的实现。在这里采用该模式,我们更加关注其在真正核心方法调用前后的扩展机制、以及核心方法的阻断机制,以及最终扩展 API 提供的形式。

 

实现


该模式放到 Rafy 中实现提交时的扩展点后,类图如下:

 

扩展点使用方法也较简单,使用者继承拦截器,编写相应的扩展逻辑即可:

有一个细节需要注意:上图中能看到,方法的第一个参数也是一个自定义的参数类型 SubmitArgs。但是由于拦截器是一种链式调用,所以这个类型可以采用值类型;在此方法被大量调用时,相对于事件的扩展机制,没有大量的冗余对象。

在启动时,加入以下代码就可以把该拦截器添加到保存的拦截器列表中:

 

总结


拦截器模式实现起来比较简单,该模式的结构非常类似于 GOF 中的职责链模式,只是关注点不同。在使用它作为扩展点时,对于使用者来说也比较易用,而且性能相对于事件机制来说更好,所以可以直接作为一种常用的扩展点设计方案。

时间: 2024-11-02 18:28:28

巧用拦截器:高效的扩展点设计的相关文章

shiro 拦截器链

Shiro使用了与Servlet一样的Filter接口进行扩展:所以如果对Filter不熟悉可以参考<Servlet3.1规范>http://www.iteye.com/blogs/subjects/Servlet-3-1了解Filter的工作原理.首先下图是Shiro拦截器的基础类图: 1.NameableFilter NameableFilter给Filter起个名字,如果没有设置默认就是FilterName:还记得之前的如authc吗?当我们组装拦截器链时会根据这个名字找到相应的拦截器实

springMVC3.0(文件上传,@RequestMapping加参数,@SessionAttributes,@ModelAttribute,转发,重定向,数值获取,传参,ajax,拦截器)

1.项目包结构如下: 2.       spring配置文件springMVC.xml修改如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xml

Struts2之拦截器篇

拦截器是Struts2框架的核心和基础,Struts2绝大多数功能都是通过拦截器来完成的,当StrutsPrepareAndExecuteFilter拦截到用户请求后,大量拦截器会对该请求进行处理,然后才调用用户自定义的Action类中的方法进行处理请求,由此可见,拦截器是Struts2的核心所在. Struts2框架内建了大量的拦截器,我们可以在struts-default.xml中进行查看: 那么这些内置拦截器的具体作用是什么呢?     alias 实现在不同请求中相似参数别名的转换 au

JavaWeb过滤器的运行机制理解及过滤器.监听器.拦截器-原理&amp;区别

过滤器Filter 一.过滤器的概念. Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.压缩响应信息等一些高级功能. 二.过滤器的运行机制.   没有加Filter的web项目运行机制如下:   加上Filter的web运行机制: 由此可见:Filter的作用

SpringMVC拦截器实现登录认证_java

博客以Demo的形式讲诉拦截器的使用 项目结构如图: 需要的jar:有springMVC配置需要的jar和jstl需要的jar SpringMVC包的作用说明: aopalliance.jar:这个包是AOP联盟的API包,里面包含了针对面向切面的接口.通常spring等其它具备动态织入功能的框架依赖这个jar spring-core.jar:这个jar 文件包含Spring 框架基本的核心工具类.Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统

拦截器问题 谢谢-不进Struts拦截器,麻烦帮解决,谢谢~~~~~

问题描述 不进Struts拦截器,麻烦帮解决,谢谢~~~~~ test.jsp <%@ page contentType="text/html;charset=GB2312"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

Java的Struts框架中Action的编写与拦截器的使用方法_java

Struts2 Action/动作动作是Struts2框架的核心,因为他们的任何MVC(模型 - 视图 - 控制器)框架.每个URL将被映射到一个特定的动作,它提供了来自用户的请求提供服务所需的处理逻辑. 但动作也提供其他两个重要的能力.首先,操作从请求数据的传输中起着重要的作用,通过向视图,无论是一个JSP或其它类型的结果.二,动作必须协助的框架,在确定结果应该渲染视图,在响应该请求将被退回. 创建动作:在Struts2的动作,唯一的要求是必须有一个无参数的方法返回String或结果的对象,必

配置-求助,SSH整合后拦截器不起作用

问题描述 求助,SSH整合后拦截器不起作用 struts.xml配置如下 <interceptors> <interceptor name="loginInterceptor" class="com.music.interceptor.LoginInterceptor"></interceptor> <interceptor-stack name="globalInterceptor"> <i

Flume-NG源码阅读:SourceRunner及选择器selector和拦截器interceptor的执行

在AbstractConfigurationProvider类中loadSources方法会将所有的source进行封装成SourceRunner放到了Map<String, SourceRunner> sourceRunnerMap之中.相关代码如下: Map<String, String> selectorConfig = context.getSubProperties( BasicConfigurationConstants.CONFIG_SOURCE_CHANNELSEL