首页 > Java > 高级篇 > 责任链设计模式(过滤器、拦截器)
2014
09-07

责任链设计模式(过滤器、拦截器)

责任链设计模式(Chain of Responsibility)的应用有:Java Web中的过滤器链、Struts2中的拦截器栈。

先看一个问题:

给定一个字符串“被就业了:),敏感信息,<script>”,对其中的HTML标记和敏感词进行过滤或替换。
本文主要以该问题设计方法的演变来讲解责任链设计模式。

第一种设计:没有任何设计模式

设计了一个MsgProcessor类,完成字符串处理的主要工作。MainClass类是本设计中的测试类。

public class MainClass {
	public static void main(String[] args) {
		//需要被过滤的语句
		String msg = "被就业了:),敏感信息,<script>";

		//实例化处理类
		MsgProcessor mp = new MsgProcessor(msg);
		String r = mp.process();

		System.out.println(r);
	}

}

public class MsgProcessor {
	private String msg;
	public MsgProcessor(String msg){
		this.msg = msg;
	}

	public String process(){
		String r = msg;
		//过滤msg中的HTML标记
		r = r.replace("<", "&lt;").replace(">", "&gt;");
		//过滤敏感词
		r = r.replace("敏感", "").replace("被就业", "就业");

		return r;
	}
}

第二种设计:增加一个Filter接口

在第一种设计中,对字符串的所有处理都放在MsgProcessor类中,扩展性极差。如果要过滤字符串中的笑脸(将”:)”替换成”^_^”),则需要改动MSgProcessor中的process方法。

public interface Filter {
	String doFilter(String str);
}

public class HtmlFilter implements Filter {
	public String doFilter(String msg) {
		String r = msg;
		//过滤msg中的HTML标记
		r = r.replace("<", "&lt;").replace(">", "&gt;");

		return r;
	}
}

public class SensitiveFilter implements Filter {
	public String doFilter(String msg) {
		String r = msg;
		//过滤敏感词
		r = r.replace("敏感", "").replace("被就业", "就业");

		return r;
	}
}

public class MsgProcessor {
	private String msg;
	private Filter[] filters = {new HtmlFilter(),new SensitiveFilter()};

	public MsgProcessor(String msg){
		this.msg = msg;
	}

	public String process(){
		String r = msg;
		for(Filter f : filters){
			r = f.doFilter(r);
		}
		return r;
	}
}

此时,如果需要过滤字符串中的笑脸,只需要创建一个类FaceFilter实现Filter接口,并在MsgProcessor类中的filters字段中登记即可。

第三种设计:责任链模式(FilterChain)

定义:将一个事件处理流程分派到一组执行对象上去,这一组执行对象形成一个链式结构,事件处理请求在这一组执行对象上进行传递。责任链模式的主要参与角色:

① 事件处理请求对象(Request)

② 执行对象(Handler)

责任链设计模式(过滤器、拦截器)1838

public class FilterChain implements Filter {

	public List<Filter> filters= new ArrayList<Filter>();

	public FilterChain addFilter(Filter f){
		filters.add(f);
		return this;
	}

	public String doFilter(String msg) {//执行filters中的doFilter方法即可
		String r = msg;
		for(Filter f : filters){
			r = f.doFilter(r);
		}
		return r;
	}
}

public class MsgProcessor {
	private String msg;
	private FilterChain chain = new FilterChain();

	public MsgProcessor(String msg,Filter Chain){
		this.msg = msg;
		this.chain = chain;
	}

	public String process(){
		return chain.doFilter(msg);
	}
}

public class MainClass {
	public static void main(String[] args) {
		//需要被过滤的语句
		String msg = "被就业了:),敏感信息,<script>";

		//搞一个过过滤链
		FilterChain chain = new FilterChain();
		chain.addFilter(new HtmlFilter()).addFilter(new SensitiveFilter());
		//实例化处理类
		MsgProcessor mp = new MsgProcessor(msg,chain);
		String r = mp.process();

		System.out.println(r);
	}
}

责任链模式加强版
上面的实现的过滤链可以用下图a)表示出来,整个过程只对msg过滤了一次。而JavaWeb中的过滤器链和Struts2中的拦截器栈执行的过程可以形象的表示为图b,☆很重要)。

责任链设计模式(过滤器、拦截器)2890

下面用程序模拟JavaWeb中的过滤器,实现类似于对Request和Response的过滤。主要涉及的类如下所示:

责任链设计模式(过滤器、拦截器)2950

public interface Filter {
	void doFilter(Request req,Response resp,FilterChain chain);
}

public class HtmlFilter implements Filter {
	public void doFilter(Request req, Response resp, FilterChain chain) {
		//过滤req.reqStr中的HTML标记
		req.reqStr = req.reqStr.replace("<", "&lt;").replace(">", "&gt;");
		req.reqStr += "---HtmlFilter()---";
		chain.doFilter(req, resp);
		resp.respStr += "---HtmlFilter()---";
	}
}

public class SensitiveFilter implements Filter {
	public void doFilter(Request req, Response resp, FilterChain chain) {
		// 过滤req.reqStr中的敏感词
		req.reqStr = req.reqStr.replace("敏感", "").replace("被就业", "就业");
		req.reqStr += "===SensitiveFilter";
		chain.doFilter(req, resp);
		resp.respStr += "===SensitiveFilter";
	}
}

public class FilterChain{
	private List<Filter> filters = new ArrayList<Filter>();
	//调用链上的过滤器时,记录过滤器的位置用
	private int index = 0;

	public FilterChain addFilter(Filter f){
		filters.add(f);
		return this;
	}

	public void doFilter(Request req, Response resp) {
		if(index == filters.size()) return;
		//得到当前过滤器
		Filter f = filters.get(index);
		index++;

		f.doFilter(req, resp, this);
	}
}

public class Request {
	//在Request中只保持了一个reqStr字段记录对Request的操作
	//为了方便模拟,没有将reqStr设置为private
	String reqStr;
}

public class Response {
	//在Response中只保持了一个respStr字段记录对Response的操作
	//为了方便模拟,没有将respStr设置为private
	String respStr;
}
package org.flyne.fiter;

public class MainClass {
	public static void main(String[] args) {
		// 需要被过滤的语句
		String msg = "被就业了:),敏感信息,<script>";

		//创建Request、Response对象
		Request req = new Request();
		Response resp = new Response();
		req.reqStr = msg;
		resp.respStr = "response";

		//搞一个过滤链,链上有两个过滤器
		FilterChain chain = new FilterChain();
		chain.addFilter(new HtmlFilter())
			.addFilter(new SensitiveFilter());

		//开始过滤
		chain.doFilter(req, resp);

		System.out.println(req.reqStr);
		System.out.println(resp.respStr);
	}
}

责任链设计模式(过滤器、拦截器)》有 6 条评论

  1. 欲风 说:

    加强版怎么过滤两次了。。没看出来……

    • 汪杰宇 说:

      在A方法中调用B方法,当B方法执行结束后回到A方法向下继续执行。在Filter.doFilter的两个实现方法中(A方法),均调用了chain.doFilter(B方法),调用之前过滤一次(过滤request对象),调用之后回到A方法,又过滤一次(过滤response对象)。

留下一个回复

你的email不会被公开。