责任链模式,做个东西我们可能自己虽然没有亲手动手写过类似的代码,但是在实际的码农生涯中肯定是有过类似的接触的,特别是Java Web的开发者,比如什么Filter,拦截器,多个AOP形成的拦截器链肯定会遇到一个你希望一步步的走下去的,多个人按照顺序的执行。
- 责任链的图
看图知道有啥特点:父类Handler的实现类中,有个和自身相同类的组合实例,通过实例就可以不断的一个接一个处理HandleProcess方法。说起来不是特别的好懂,看代码。
简单的责任链模式
- Handler
/**
* descrption: 创建责任链模式
* authohr: wangji
* date: 2017-09-23 9:36
*/
public abstract class Handler {
private Handler sucessor;//接班人
public void setSucessor(Handler sucessor) {
this.sucessor = sucessor;
}
/**
* @desction: 1.首先执行自身的;2.然后调用责任链中的下一个继承者
* @author: wangji
* @date: 2017/9/23
* @param:
* @return:
*/
public void execute(){
handleProcess();
if(sucessor != null){
sucessor.execute();
}
}
protected abstract void handleProcess();
}
- Handler的实现A
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ConcreteHandlerA extends Handler {
@Override
protected void handleProcess() {
log.info("handle by ConcreteHandlerA");
}
}
- Client的实现,看看效果
/**
* descrption: 创建和调用责任链
* authohr: wangji
* date: 2017-09-23 9:45
*/
public class Client {
public static void main(String[] args) {
ConcreteHandlerA ConcreteHandlerA = new ConcreteHandlerA();
ConcreteHandlerB ConcreteHandlerB = new ConcreteHandlerB();
ConcreteHandlerC ConcreteHandlerC = new ConcreteHandlerC();
//A->B-C
ConcreteHandlerA.setSucessor(ConcreteHandlerB);
ConcreteHandlerB.setSucessor(ConcreteHandlerC);
ConcreteHandlerA.execute();
//这里比较的麻烦,每次都是需要依次的处理一个个后继
}
}
//2017-09-23 11:29:33,027 INFO [ConcreteHandlerA.java:9] : handle by ConcreteHandlerA
//2017-09-23 11:29:33,030 INFO [ConcreteHandlerB.java:10] : handle by ConcreteHandlerB
//2017-09-23 11:29:33,031 INFO [ConcreteHandlerC.java:10] : handle by ConcreteHandlerC
但是上面的比较麻烦,每次都需要对下个执行者进行依次的设置其信息,不太舒服,进行改进一下比较好。将Handler的实现者保存到一个Chain中的成员变量的List中,每次每个Handler的实现者都有Chain的引用,这样就可以通过改变下标,依次的执行。可能不太好理解,看看代码就懂了。
- ChainHandler
/**
* descrption:通过传入Chain中保存了ChainHanler的List,然后遍历,通过下标标识。由于有Chain的对象,可以调用其方法
* authohr: wangji
* date: 2017-09-23 9:55
*/
public abstract class ChainHandler {
public void execute(Chain chain){
handleProcess();
chain.proceed();
}
protected abstract void handleProcess();
}
- ChainHandler的实现者
import lombok.extern.slf4j.Slf4j;
/**
* descrption:
* authohr: wangji
* date: 2017-09-23 9:58
*/
@Slf4j
public class ConcreteHandlerA extends ChainHandler {
protected void handleProcess() {
log.info("handle by ConcreteHandlerA");
}
}
- 重点的Chain
import java.util.List;
/**
* descrption: 责任链模式的升级处理,不要每次都去处理后继者
* http://blog.csdn.net/justloveyou_/article/details/68491121
* 这个博客自己手动写责任链模式有点类似
* authohr: wangji
* date: 2017-09-23 9:54
*/
public class Chain {
private List<ChainHandler> handlers;
private int index = 0;
public Chain(List<ChainHandler> handlers) {
this.handlers = handlers;
}
public void proceed(){
if(index >= handlers.size()){
return ;
}
handlers.get(index++).execute(this);
}
}
- Client的使用
/**
* descrption:升级版Chain模式,不需要为每一个具体的实现确定一个下一继承者
* authohr: wangji
* date: 2017-09-23 10:32
*/
public class ChainClient {
public static void main(String[] args) {
//这里的处理也是一样的,只是不需要为每一个设置下一继承者,在确定List的时候就通过自身的下标确定了。
List<ChainHandler> handlers = Arrays.asList(
new ConcreteHandlerA(),
new ConcreteHandlerB(),
new ConcreteHandlerC()
);
Chain chain = new Chain(handlers);
chain.proceed();
}
}
实际场景的应用
参考文档实现原理
图:
- Filter
/**
* descrption:模拟Servlet的Filter
* authohr: wangji
* date: 2017-09-23 11:45
*/
public interface Filter {
//每个Filter均为FilterChain的成员, Filter持有FilterChain的引用,以便调用链条中的各处理者
void doFilter(Request request, Response response, FilterChain chain);
}
- 实现Filter(替换我的名字)
import lombok.extern.slf4j.Slf4j;
/**
* descrption: 简单的模拟过滤器替换一个姓名
* authohr: wangji
* date: 2017-09-23 13:23
*/
@Slf4j
public class ConcreteFileterA implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
log.info("ConcreteFileterA replace wangji to 汪吉 begin");
String msg = request.getRequest().replace("wangji", "汪吉");
request.setRequest(msg);
chain.doFilter(request, response);
response.setResponse(response.getResponse() + "--->replace wangji to 汪吉");
log.info("ConcreteFileterA replace wangji to 汪吉 end");
}
}
- 添加一个字符串
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ConcreteFileterB implements Filter {
public void doFilter(Request request, Response response, FilterChain chain) {
log.info("ConcreteFileterB add String: \"add a String\"; begin");
String msg = request.getRequest()+" add a String";
request.setRequest(msg);
chain.doFilter(request, response);
response.setResponse(response.getResponse() + "--->add String: \"add a String\";");
log.info("ConcreteFileterB add String: \"add a String\"; end");
}
}
- 重点的FilterChain和上面的升级的责任链模式类似
/**
- descrption: 过滤链的抽象
- authohr: wangji
- date: 2017-09-23 11:44
*/
public class FilterChain {
List<Filter> filters = new ArrayList<Filter>();
int index = 0;
// 链式编程
public FilterChain addFilter(Filter filter){
filters.add(filter);
return this;
}
public void doFilter(Request request, Response response) {
if(index == filters.size()) return;
Filter filter = filters.get(index);
index++;
filter.doFilter(request, response, this);//拥有过滤链的抽象
}
}
- 简单模拟请求和返回内容
public class Request {
// 请求消息
private String request;
public String getRequest() {
return request;
}
public void setRequest(String request) {
this.request = request;
}
}
public class Response {
// 响应消息
private String response;
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}
- 测试模拟的
/**
* descrption:测试模拟的Filter
* authohr: wangji
* date: 2017-09-23 13:31
*/
@Slf4j
public class Client {
public static void main(String[] args) {
ConcreteFileterA concreteFileterA = new ConcreteFileterA();
ConcreteFileterB concreteFileterB = new ConcreteFileterB();
FilterChain filterChain = new FilterChain();
filterChain.addFilter(concreteFileterA)
.addFilter(concreteFileterB);
// 待处理消息
String msg = "This is an analog filter,my request msg is:wangji is a boy";
Request request = new Request();
request.setRequest(msg);
Response response = new Response();
response.setResponse("Response");
filterChain.doFilter(request,response);
log.info("file end request str:"+request.getRequest());
log.info("file end reponse str:"+response.getResponse());
}
}
//2017-09-23 13:37:54,551 INFO [ConcreteFileterA.java:13] : ConcreteFileterA replace wangji to 汪吉 begin
//2017-09-23 13:37:54,554 INFO [ConcreteFileterB.java:9] : ConcreteFileterB add String: "add a String"; begin
//2017-09-23 13:37:54,555 INFO [ConcreteFileterB.java:14] : ConcreteFileterB add String: "add a String"; end
//2017-09-23 13:37:54,555 INFO [ConcreteFileterA.java:18] : ConcreteFileterA replace wangji to 汪吉 end
//2017-09-23 13:37:54,555 INFO [Client.java:29] : file end request str:This is an analog filter,my request msg is:汪吉 is a boy add a String
//2017-09-23 13:37:54,556 INFO [Client.java:30] : file end reponse str:Response--->add String: "add a String";--->replace wangji to 汪吉