设计模式——责任链模式

本文介绍责任链模式。

概念

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

结构和工作原理

  • Handler:抽象处理者,定义处理请求的抽象接口。
  • ConcreteHandler:具体抽象者,抽象处理者的子类,用于处理和传递请求。

责任链模式就像一个流水线,一个请求顺着链不断地被“加工”直到结束,每个责任链上的节点都有两个职责,处理请求、转发请求。由此每个处理者都会持有下一个处理者的引用方便传递请求,同时实现抽象处理者的接口完成处理请求的职责。

责任链模式有两种:

  • 纯的责任链:要求请求只能被链上的一个处理者处理,不允许处理者同时既处理请求又把请求传递的情况
  • 不纯的责任链:不纯的责任链上的每一个处理者都可以对请求进行判断处理,同时会把请求传递给下一个处理者

通常责任链的实现都是不纯的责任链。

优点:

  • 责任链模式将每个职责都划分内聚到每个处理者中
  • 责任链模式中各个处理者可以自由编排顺序
  • 处理者之间的耦合度很低,可以方便的添加处理者

缺点:

  • 类会很多,调试起来不太方便

代码示例

Pure

public abstract class AbstractHandler {

public enum Condition{
A,B
}

protected AbstractHandler nextHandler;

public abstract void handle(Condition condition, String request);

public AbstractHandler(AbstractHandler nextHandler) {
this.nextHandler = nextHandler;
}

}
@Slf4j
public class ConcreteHandlerA extends AbstractHandler {

public ConcreteHandlerA(AbstractHandler nextHandler) {
super(nextHandler);
}

@Override
public void handle(Condition condition, String request) {
if (condition.equals(Condition.A)) {
log.info("ConcreteHandlerA- handle request:{}", request);
return;
}
if (nextHandler != null) {
nextHandler.handle(condition, request);
}
}
}
@Slf4j
public class ConcreteHandlerB extends AbstractHandler {

public ConcreteHandlerB(AbstractHandler nextHandler) {
super(nextHandler);
}

@Override
public void handle(Condition condition, String request) {
if (condition.equals(Condition.B)) {
log.info("ConcreteHandlerB- handle request:{}", request);
return;
}
if (nextHandler != null) {
nextHandler.handle(condition, request);
}
}
}
public class CoRPureClient {

private static AbstractHandler handlerChain;

private static void init() {
AbstractHandler handlerA = new ConcreteHandlerA(null);
handlerChain = new ConcreteHandlerB(handlerA);
}

public static void main(String[] args) {
init();
handlerChain.handle(AbstractHandler.Condition.A, "requestA");
handlerChain.handle(AbstractHandler.Condition.B, "requestB");
}
}

Nonpure

该例子是参考Alibaba-Sentinel功能插槽Slot实现的,核心思想也是责任链模式。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Request {

private String auth;

private Integer level;

private Boolean shouldPass = true;

}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Response {

private String result = "";

}
public interface Filter {

// 具体的处理逻辑
void doFilter(Request request, Response response);

// 传递给下一个Filter
void fireFilter(Request request, Response response);

}
public abstract class AbstractFilter implements Filter {

private AbstractFilter nextFilter;

// 重写 fireFilter 对下一个Filter是否存在做了判断
@Override
public void fireFilter(Request request, Response response) {
if (nextFilter != null) {
nextFilter.transformEntry(request, response);
}
}

// 对 doFilter 加了一个判断,用于提前结束流转
void transformEntry(Request request, Response response) {
if (request.getShouldPass()) {
doFilter(request, response);
}
}

public AbstractFilter getNextFilter() {
return nextFilter;
}

public void setNextFilter(AbstractFilter nextFilter) {
this.nextFilter = nextFilter;
}
}
@Slf4j
public class AuthFilter extends AbstractFilter {

private static Gson gson = new Gson();

public static final String AUTH = "AUTH";

@Override
public void doFilter(Request request, Response response) {
String preResult = response.getResult();
if (AUTH.equals(request.getAuth())) {
response.setResult(preResult + "auth check pass");
} else {
response.setResult(preResult + "auth check failure");
request.setShouldPass(false);
}
log.info("AuthFilter- doFilter- request:{} ,response:{}", gson.toJson(request), gson.toJson(response));
fireFilter(request, response);
}
}
@Slf4j
public class LevelFilter extends AbstractFilter {

private static Gson gson = new Gson();

@Override
public void doFilter(Request request, Response response) {
String preResult = response.getResult();
if (request.getLevel() > 0) {
response.setResult(preResult + "level check pass");
} else {
response.setResult(preResult + "level check failure");
request.setShouldPass(false);
}
log.info("LevelFilter- doFilter- request:{} , response:{}", gson.toJson(request), gson.toJson(response));
fireFilter(request, response);
}
}
public class FilterChain extends AbstractFilter {

private AbstractFilter firstFilter = new AbstractFilter() {
@Override
public void doFilter(Request request, Response response) {
super.fireFilter(request, response);
}
};

private AbstractFilter end = firstFilter;

@Override
public void doFilter(Request request, Response response) {
firstFilter.transformEntry(request, response);
}

public void addLast(AbstractFilter filter) {
end.setNextFilter(filter);
end = filter;
}
}
@Slf4j
public class CoRNonPureClient {

private static FilterChain filterChain;

private static Gson gson = new Gson();

private static void init() {
filterChain = new FilterChain();
filterChain.addLast(new AuthFilter());
filterChain.addLast(new LevelFilter());
}

public static void main(String[] args) {
init();
Request requestA = Request.builder().auth("auth").level(1).shouldPass(true).build();
Response responseA = Response.builder().result("").build();
filterChain.doFilter(requestA, responseA);
log.info("Client- main- result- response: {}", gson.toJson(responseA));

Request requestB = Request.builder().auth("AUTH").level(1).shouldPass(true).build();
Response responseB = Response.builder().result("").build();
filterChain.doFilter(requestB, responseB);
log.info("Client- main- result- response: {}", gson.toJson(responseB));

Request requestC = Request.builder().auth("AUTH").level(-1).shouldPass(true).build();
Response responseC = Response.builder().result("").build();
filterChain.doFilter(requestC, responseC);
log.info("Client- main- result- response: {}", gson.toJson(responseC));
}
}

参考资料

https://github.com/CyC2018/CS-Notes/blob/master/notes/设计模式 - 责任链.md
https://www.cnblogs.com/kubixuesheng/p/5182611.html
https://github.com/alibaba/Sentinel

Author: nopainanymore
Link: http://nopainanymore.me/DesignPattern-ChainOfResponsibility/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
wechat