JAVA设计模式之责任链模式

责任链模式在设计模式里边属于比较难的设计模式,主要用于对一个对象进行一系列的操作,每个操作相互独立。这一系列的操作组成了一个操作链,每个操作都有其具体的职责,即是一个责任链。

UML图如下

先用一个简单的例子来体验一下责任链模式,假设有个程序需要接收一个消息,但是这个消息需要进行过滤,比如HTML,JS的转义,敏感字符的替换等。

定义一个消息类,只有消息这一个属性;定义一个过滤器,只有过滤这一个方法,然后给出三个实现,分别用于HTML,JS和敏感字符的过滤。

public class Msg {

	private String text;

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	@Override
	public String toString() {
		return text;
	}
}

public interface Filter {

	/**
	 * 过滤方法
	 * @param msg
	 * @return true:继续执行; false: 不继续执行
	 */
	boolean doFilter(Msg msg);
}

public class HTMLFilter implements Filter {

	@Override
	public boolean doFilter(Msg msg) {
		String text = msg.getText();
		text = text.replaceAll("<", "[");
		text = text.replaceAll(">", "]");
		msg.setText(text);
		return true;
	}

}

public class JSFilter implements Filter {

	@Override
	public boolean doFilter(Msg msg) {
		String text = msg.getText();
		msg.setText(text.replaceAll("javascript", "cdth"));
		return true;
	}

}

public class SensitiveFilter implements Filter{

	private final String sensitiveText = "996" ;
	
	@Override
	public boolean doFilter(Msg msg) {
		String text = msg.getText();
		msg.setText(text.replaceAll(sensitiveText, "955"));
		return false;
	}

}

责任链模式最主要的地方就是实现责任链,我们可以定义一个类,维护一个过滤器的集合,在调用过滤方法的时候把集合里的过滤器遍历,依次调用其自身的过滤方法,且根据返回值来判断过滤器链要不要继续往下执行。这里可以看到,过滤器链本身也实现了Filter接口,这说明我们可以把该过滤器链接到其他的过滤器链的后边。

public class FilterChain implements Filter {

	private List<Filter> filters = new ArrayList<>();
	
	public FilterChain addFilter(Filter filter) {
		filters.add(filter);
		return this;
	}
	
	@Override
	public boolean doFilter(Msg msg) {
		for (Filter filter : filters) {
			if(!filter.doFilter(msg)) {
				return false;
			}
		}
		return true;
	}

}

测试一下。

public class Main {

	public static void main(String[] args) {
		Msg msg = new Msg();
		msg.setText("<p>i love javascript</p><p>i hate 996</p>");
		FilterChain chain = new FilterChain();
		chain.addFilter(new HTMLFilter())
			.addFilter(new SensitiveFilter())
			.addFilter(new JSFilter());
		chain.doFilter(msg);
		System.out.println(msg);
	}
}

在JAVAEE 中,过滤器Filter接口其实就是一种责任链模式的实现,简单写个DEMO来模仿一下Filter的原理。

首先我们需要ServletRequest,ServletResponse,和FilterChain 三个对象,其中ServletRequest,ServletResponse只有一个属性Body,FilterChain对象暂时没有任何东西。

public class ServletRequest {

	private String body;

	public String getBody() {
		return body;
	}

	public void setBody(String body) {
		this.body = body;
	}

	@Override
	public String toString() {
		return body;
	}
}

public class ServletResponse {
	
	private String body;
	
	public String getBody() {
		return body;
	}

	public void setBody(String body) {
		this.body = body;
	}

	@Override
	public String toString() {
		return body;
	}
}

public class FilterChain {
}

然后,我们需要一个Filter接口,用于对ServletRequest和ServletResponse进行过滤,且可以顺着过滤器链一直往下执行。所以Filter接口需要三个参数ServletRequest,ServletResponse和FilterChain。其中让过滤器开始工作的入口是过滤器链提供的,所以FilteChain需要有一个方法(public void doFilter(ServletRequest request, ServletResponse response) )来让过滤器链中的过滤器开始工作。再添加三个Filter接口的实现,同样是对HTML,JS,敏感词的过滤。

public interface Filter {

	void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);

}

public class FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response) {}

}

public class HTMLFilter implements Filter{

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
		// start process request
		String body = request.getBody();
		body = body.replaceAll("<", "[");
		body = body.replaceAll(">", "]");
		request.setBody(body + " --html filter");
		// next filter of chain start process request 
		chain.doFilter(request, response);
		// request process finished, start process response
		response.setBody(response.getBody() + " --html filter");
	}

}

public class JSFilter implements Filter{

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
		// start process request
		request.setBody(request.getBody().replaceAll("javascript", "cdth") + " --js filter");
		// next filter of chain start process request 
		chain.doFilter(request, response);
		// request process finished, start process response
		response.setBody(response.getBody() + " --js filter");
	}

}

public class SensitiveFilter implements Filter{

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
		// start process request
		request.setBody(request.getBody().replaceAll("996", "955") + " --sensitive filter");
		// next filter of chain start process request 
		chain.doFilter(request, response);
		// request process finished, start process response
		response.setBody(response.getBody() + " --sensitive filter");
	}

}

可以看到每个过滤器的实现都是先处理request,再交给链条中的下一个过滤器去处理request,然后再处理response。因为JAVAEE标准就是对request的处理和对response的处理,其顺序是正好相反的;例如,处理request的顺序是HTMLFilter,JSFilter,SensitiveFilter,那么处理repsonse的顺序就是SensitiveFilter,JSFilter,HTMLFilter。其实Spring MVC的拦截器调用preHandle和postHandle的顺序,也是这样的。

现在需要做的就是实现FilterChain,首先肯定需要把过滤器都存起来,所以需要集合和addFilter方法。重点就在于doFilter方法,为了保证上述的顺序,需要有一个index来保证当前使用的过滤器。

以下是FilterChain的完整实现。

public class FilterChain {

	private List<Filter> filters = new ArrayList<>();
	
	private int index;

	public FilterChain addFilter(Filter filter) {
		filters.add(filter);
		return this;
	}
	
	public void doFilter(ServletRequest request, ServletResponse response) {
		if(index < filters.size()) {
			Filter filter = filters.get(index);
			index++;
			filter.doFilter(request, response, this);
		}
	}
	
}

测试一下。

public class Main {

	public static void main(String[] args) {
		ServletRequest request = new ServletRequest();
		request.setBody("<p>i love javascript</p><p>i hate 996</p>");
		ServletResponse response = new ServletResponse();
		response.setBody("response");
		FilterChain chain = new FilterChain();
		chain.addFilter(new HTMLFilter())
			.addFilter(new SensitiveFilter())
			.addFilter(new JSFilter());
		chain.doFilter(request,response);
		System.out.println("---------request-----------");
		System.out.println(request.getBody());
		System.out.println("---------response-----------");
		System.out.println(response.getBody());
	}

}

运行之后,程序确实如期的执行。

现在再回到Filter上来,虽然我们把三个过滤器都添加进了过滤器链,但是如果我其中的一个过滤器没有去让链条往下执行,那么链条实际上会在这个过滤器的地方“递归回去”。

现在 SensitiveFilter 处于链条中的第二个位置,如果我把chain.doFilter(request, response)注释掉,那么过滤器链就会在他这里终止不会去找下一个过滤器即JSFilter。

public class SensitiveFilter implements Filter{

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
		// start process request
		request.setBody(request.getBody().replaceAll("996", "955") + " --sensitive filter");
		// next filter of chain start process request 
		//chain.doFilter(request, response);
		// request process finished, start process response
		response.setBody(response.getBody() + " --sensitive filter");
	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值