Java 中的责任链模式:构建健壮的请求处理机制
大约 4 分钟
也称为
- 命令链
- 对象链
- 责任链
责任链设计模式的意图
Java 中的责任链模式是一种行为型设计模式,它通过让多个对象有机会处理请求来解耦请求的发送者和接收者。接收对象被链接在一起,请求沿着链传递,直到某个对象处理它。
责任链模式的详细解释以及现实世界中的例子
现实世界中的例子
Java 中责任链模式的现实世界例子是技术支持呼叫中心。在实现此 Java 设计模式时,每个支持级别代表链中一个处理程序。当客户致电寻求帮助时,首先由一线支持人员接听电话。如果问题很简单,支持人员会直接处理它。如果问题比较复杂,支持人员会将电话转接给二线支持技术人员。这个过程会一直持续,电话会不断升级到多个支持级别,直到到达可以解决问题的专家。每个支持级别代表链中的一个处理程序,电话沿着链传递,直到找到合适的处理程序,从而解耦请求和特定接收者。
简单来说
它有助于构建一连串对象。请求从一端进入,并在对象之间传递,直到找到合适的处理程序。
维基百科说
在面向对象的设计中,责任链模式是一种设计模式,它由一个命令对象源和一系列处理对象组成。每个处理对象包含定义它可以处理的命令对象类型的逻辑;其余的命令对象将传递给链中的下一个处理对象。
责任链模式的编程示例
在这个 Java 例子中,兽人国王发出命令,这些命令由代表责任链模式的命令链处理。以下代码片段将教您如何在 Java 中实现此设计模式。
兽人国王向他的军队发出响亮的命令。最接近的人是指挥官,然后是军官,最后是士兵。指挥官、军官和士兵组成了责任链。
首先,我们有 Request
类
@Getter
public class Request {
private final RequestType requestType;
private final String requestDescription;
private boolean handled;
public Request(final RequestType requestType, final String requestDescription) {
this.requestType = Objects.requireNonNull(requestType);
this.requestDescription = Objects.requireNonNull(requestDescription);
}
public void markHandled() {
this.handled = true;
}
@Override
public String toString() {
return getRequestDescription();
}
}
public enum RequestType {
DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
}
接下来,我们展示 RequestHandler
层次结构。
public interface RequestHandler {
boolean canHandleRequest(Request req);
int getPriority();
void handle(Request req);
String name();
}
@Slf4j
public class OrcCommander implements RequestHandler {
@Override
public boolean canHandleRequest(Request req) {
return req.getRequestType() == RequestType.DEFEND_CASTLE;
}
@Override
public int getPriority() {
return 2;
}
@Override
public void handle(Request req) {
req.markHandled();
LOGGER.info("{} handling request \"{}\"", name(), req);
}
@Override
public String name() {
return "Orc commander";
}
}
// OrcOfficer and OrcSoldier are defined similarly as OrcCommander ...
OrcKing
发出命令并形成链。
public class OrcKing {
private List<RequestHandler> handlers;
public OrcKing() {
buildChain();
}
private void buildChain() {
handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
}
public void makeRequest(Request req) {
handlers
.stream()
.sorted(Comparator.comparing(RequestHandler::getPriority))
.filter(handler -> handler.canHandleRequest(req))
.findFirst()
.ifPresent(handler -> handler.handle(req));
}
}
责任链在行动中。
public static void main(String[] args) {
var king = new OrcKing();
king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
}
控制台输出
Orc commander handling request "defend castle"
Orc officer handling request "torture prisoner"
Orc soldier handling request "collect tax"
责任链模式类图

何时在 Java 中使用责任链模式
在以下情况下使用责任链模式
- 多个对象可能处理一个请求,而处理程序事先未知。处理程序应自动确定。
- 您希望向多个对象中的一个发出请求,而无需显式指定接收者。
- 可以动态指定可以处理请求的对象集。
责任链模式在 Java 中的现实世界应用
- GUI 框架中的事件冒泡,其中事件可能在 UI 组件层次结构的多个级别进行处理
- 中间件框架,其中请求通过一系列处理对象传递
- 日志框架,其中消息可以传递给一系列日志记录器,每个日志记录器可能以不同的方式处理它们
- java.util.logging.Logger#log()
- Apache Commons Chain
- javax.servlet.Filter#doFilter()
责任链模式的优势和权衡
优势
- 减少耦合。请求的发送者不需要知道将处理请求的具体处理程序。
- 在为对象分配职责方面提高灵活性。您可以通过更改链的成员和顺序来添加或更改处理请求的职责。
- 允许您在没有具体处理程序可以处理请求的情况下设置默认处理程序。
权衡
- 调试和理解流程可能具有挑战性,尤其是在链很长且很复杂的情况下。
- 如果链中没有包含一个万能处理程序,请求最终可能会无法处理。
- 由于可能需要遍历多个处理程序才能找到正确的处理程序,或者根本找不到,因此可能会出现性能问题。