文档章节

责任链模式

loda0128
 loda0128
发布于 2015/05/02 10:13
字数 1792
阅读 55
收藏 0

        前一段时间在工作中碰到一个问题,大概就是要模拟一系列的http请求,完整一串操作。大概是首先模拟登陆,然后在管理平台界面完整一连串的增删查改,总共大概有5、6个http请求流程,最后获取到返回信息,并以接口调用的形式传给合作方接口。因为之前看过设计模式的书,所以了解到这个流程其实跟责任链流程很相似,并且中间可能会有某个流程出现改动被删除或者又要新添加一个流程,为了尽量减少变化,我决定采用责任链模式。这样的好处是显著的,第一,减少了每个http请求流程之前的耦合,上一个操作不需要知道下一个操作是什么;第二,将流程之间互相调用的关系放在了配置文件中,一旦要变动流程,只需要改动配置文件,然后实现相应的http请求操作就行了。这里,我不会把工作中的代码拿出来,因为内容较多,我就把后来自己重写的一个过滤器工具拿出来,当你不是在web环境,或者需要自定义的request的时候,没办法使用web的filter,那么我写的这个filter,可以给你提供一些帮助。

以下就是过滤器的工作流程图:

首先是过滤器接口,如果实现了他,就要自定义过滤规则

package org.loda.service;

import org.loda.model.Request;
import org.loda.model.Response;

/**
 * 
* @ClassName: Filter 
* @Description: 过滤器接口 
* @author minjun
*
 */
public interface Filter {

	public void doFilter(Request request,Response response,FilterChain chain);
}

以下三个都是我自定义用来演示的过滤器实现,里面简略的写了以下过滤规则



package org.loda.demo;

import org.loda.model.Request;
import org.loda.model.Response;
import org.loda.service.Filter;
import org.loda.service.FilterChain;

/**
 * 
* @ClassName: EncodingFilter 
* @Description: 编码过滤器 
* @author minjun
*
 */
public class EncodingFilter implements Filter {

	@Override
	public void doFilter(Request request, Response response, FilterChain chain) {
		System.out.println("req:编码处理");
		request.setAttr("encoding", "utf-8");
		chain.doFilter(request, response);
		System.out.println("resp:编码处理");
	}

}



package org.loda.demo;

import org.loda.model.Request;
import org.loda.model.Response;
import org.loda.service.Filter;
import org.loda.service.FilterChain;

/**
 * 
* @ClassName: MessageFilter 
* @Description: 信息过滤器 
* @author minjun
*
 */
public class MessageFilter implements Filter {

	@Override
	public void doFilter(Request request, Response response, FilterChain chain) {
		System.out.println("req:数据处理");
		request.setAttr("message", "处理了信息");
		chain.doFilter(request, response);
		System.out.println("resp:数据处理");
	}

}



package org.loda.demo;

import org.loda.model.Request;
import org.loda.model.Response;
import org.loda.service.Filter;
import org.loda.service.FilterChain;

/**
 * 
* @ClassName: PermissionFilter 
* @Description:权限过滤器 
* @author minjun
*
 */
public class PermissionFilter implements Filter {

	@Override
	public void doFilter(Request request, Response response, FilterChain chain) {
		System.out.println("req:权限处理");
		request.setAttr("permission", "loda");
		chain.doFilter(request, response);
		System.out.println("resp:权限处理");
	}

}



上面的过滤器中会看到有三个参数

request表示请求信息,里面封装了一个map,如果设置request的值,相当于就是往map里面设置值,取值同理

response表示响应的信息,里面封装和操作与request相同

chain表示过滤器链,里面用一个集合存放了配置的过滤器,可以是很多个,按照在集合中的顺序调用。

package org.loda.service;

import java.util.ArrayList;
import java.util.List;

import org.loda.model.Request;
import org.loda.model.Response;
import org.loda.util.ConfigReader;

/**
 * 
* @ClassName: FilterChain 
* @Description: 过滤器链 
* @author minjun
*
 */
public class FilterChain {

	//存放所有的过滤器
	private List<Filter> filters = new ArrayList<Filter>();
	
	private int index;

	public FilterChain() {
	}

	public FilterChain(List<Filter> filters) {
		this.filters = filters;
	}
	
	/**
	 * 
	* @Title: readConfig 
	* @Description: 读取配置文件中过滤器信息(可根据需求选择性调用该方法)  
	* @param @param path 配置文件路径
	* @param @return    设定文件 
	* @return FilterChain    返回类型 
	* @throws
	 */
	public FilterChain readConfig(String path){
		List<String> str=ConfigReader.read(path);

		for(String s:str){
			try {
				Filter f=(Filter) Class.forName(s).newInstance();
				filters.add(f);
			} catch (Exception e) {
				throw new RuntimeException("找不到这个过滤器,请检查配置文件中过滤器的配置");
			}
		}
		return this;
	}
	
	/**
	 * 
	* @Title: readConfig 
	* @Description:
	*  读取配置文件中过滤器信息(可根据需求选择性调用该方法)  
	*  没有参数表示默认读取classpath下的名为filter.xml的配置文件
	* @param @return 
	* @return FilterChain    返回类型 
	* @throws
	 */
	public FilterChain readConfig(){
		return readConfig(null);
	}

	//添加过滤器
	public FilterChain addFilter(Filter filter) {
		filters.add(filter);
		return this;
	}

	//删除过滤器
	public FilterChain removeFilter(Filter filter) {
		filters.remove(filter);
		return this;
	}

	//执行过滤器
	public void doFilter(Request request, Response response) {
		//如果已经到达最后的过滤器,则返回
		if(index>=filters.size()) return;
		
		//否则调用下一个过滤器
		filters.get(index++).doFilter(request, response,this);
	}

}



上述为FilterChain的实现方案,相当于用户可以手动创建FilterChain对象,然后往里面塞过滤器;观察两个可选择性调用的重载方法readConfig,可以指定配置文件名称,读取classpath下该名称的配置文件,如果没有指定,那么默认获取名为filter.xml的配置文件。也就是,如果调用了readConfig,会将配置文件里面配置的filter全部取出来并往集合里面塞。以下是配置文件标准形式:
<?xml version="1.0" encoding="UTF-8"?>

<properties>
	<filters>
		<filter>org.loda.demo.EncodingFilter</filter>
		<filter>org.loda.demo.MessageFilter</filter>
		<filter>org.loda.demo.PermissionFilter</filter>
	</filters>
</properties>



如上图,表示过滤器执行流程会是:EncodingFilter-->MessageFilter-->PermissionFilter。

如下是测试类,包含了使用方法:

package org.loda.test;

import org.junit.Test;
import org.loda.model.Request;
import org.loda.model.Response;
import org.loda.service.FilterChain;

/**
 * 
* @ClassName: MainEntry 
* @Description:demo示例
* @author minjun
*
 */
public class MainEntry {

	@Test
	public void test() {
		//创建过滤器链
		FilterChain chain = new FilterChain()
				.readConfig()//读取配置文件(无参数表示默认配置文件路径为classpath下的filter.xml文件)
//				.readConfig("newFilter.xml")//手动指定配置文件的路径
//				.addFilter(new EncodingFilter())//添加编码过滤
//				.addFilter(new MessageFilter())//添加信息过滤
//				.addFilter(new PermissionFilter())//添加权限过滤
				;
		Request request = new Request().setAttr("begin", "helloword");
		Response response = new Response().setAttr("begin", "helloword");

		// 过滤
		chain.doFilter(request, response);

		System.out.println("处理之后的request:\n" + request);
		System.out.println("处理之后的response:\n" + request);
	}
}



整个流程是先创建过滤器链,根据情况选择是读配置文件,还是手动添加过滤器对象,或者结合使用。然后创建请求、响应对象,将数据设置进去。接着启动过滤流程。最后获取到处理信息。下面为控制台打印输出的内容,可以观察到请求时,过滤器的执行流程与我们配置的一致;响应时,执行流程反响,这与实际情况一致。并且经过过滤处理,request和response对象会有些改变。

req:编码处理
req:数据处理
req:权限处理
resp:权限处理
resp:数据处理
resp:编码处理
处理之后的request:
message:处理了信息,encoding:utf-8,permission:loda,begin:helloword
处理之后的response:
message:处理了信息,encoding:utf-8,permission:loda,begin:helloword



上面代码中看到的请求响应对象打印的形式,是我自定义的toString形式,相当于获取对象中的map,然后迭代出所有属性
@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("");
		for (Entry<String, Object> entry : map.entrySet()) {
			sb.append(entry.getKey() + ":" + entry.getValue() + ",");
		}
		if(sb.toString().endsWith(",")){
			sb.deleteCharAt(sb.length() - 1);
		}
		return sb.toString();
	}



总结,其实责任链模式理解起来灰常简单,就是一个调用另外一个,如果能保证这个调用的顺序是灵活配置的,那么使用起来会非常舒服。但是实现的代码,略微有些技巧,如果有兴趣,可以看看我osgit上的源码

https://git.oschina.net/mjaow/LFilter

(以上代码部分参考了马士兵视频写的过滤器代码,其他的配置文件等附加功能的处理都是自行解决)

© 著作权归作者所有

loda0128
粉丝 93
博文 96
码字总数 119400
作品 0
朝阳
程序员
私信 提问
JAVA设计模式之责任链模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起...

jiangmitiao
2016/03/01
75
0
Design Patterns in Android:责任链模式

前言 非常抱歉,本系列博客长达半年没更新了,今日偶得灵感,更新一波《设计模式Android篇:责任链模式》。点击此处查看《Design Patterns in Android》系列其他文章。 本文原创作者MichaelX。...

MichaelX
2018/10/30
0
0
Java设计模式学习记录-责任链模式

前言 已经把五个创建型设计模式和七个结构型设计模式介绍完了,从这篇开始要介绍行为型设计模式了,第一个要介绍的行为型设计模式就是责任链模式(又称职责链模式)。 责任链模式 概念介绍 ...

纪莫
2018/08/16
0
0
责任链模式实现费用报销的审核

责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户...

tsmyk0715
2016/07/20
10
0
我的Java设计模式-责任链模式

今天来说说程序员小猿和产品就关于需求发生的故事。前不久,小猿收到了产品的需求。 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的。 小猿:......露点?你大爷的,...

Jet啟思
2017/11/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
今天
5
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
今天
8
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
今天
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
今天
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部