责任链模式
标签 : Java与设计模式
责任链模式: 将能够处理某一类请求的对象串成一条链, 请求沿链传递, 链上的对象逐个判断是否有能力处理该请求. 使多个对象都有机会处理请求, 从而避免请求发送者和接收者之间的耦合关系.
(图片来源: 设计模式: 可复用面向对象软件的基础)
优势: 发出请求的客户端并不知道链上的哪个对象最终处理该请求, 这使得系统可以在不影响客户端的前提下动态地重新组织和分配责任.
模式实现
案例: 雇员要求 (请假 & 涨薪), 要经过总监Director -> 经理Manager -> 总经理GeneralManager的层层审批.
Handler:
定义一个处理请求的接口, 内持继任者(可选):
public abstract class Leader {
protected Leader superior;
protected String name;
protected Leader(Leader superior, String name) {
this.superior = superior;
this.name = name;
}
public abstract void handle(Request request);
}
ConcreteHandler
- 处理它所负责的请求, 可访问它的后继者;
- 如果可处理该请求, 处理之, 否则将请求转发:
// 总监
class Director extends Leader {
public Director(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 10) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总监 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 经理
class Manager extends Leader {
public Manager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 20) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 经理 [" + name + "] 审批通过");
} else if (request.getType().equals("涨薪") && request.getCount() <= 1000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 经理 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 总经理
class GeneralManager extends Leader {
public GeneralManager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假")) {
if (request.getCount() <= 30) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("[ " + request.getContent() + "] 你干脆辞职算了");
}
} else if (request.getType().equals("涨薪")) {
if (request.getCount() <= 10_000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("你咋不上天呢");
}
}
}
}
Client
向链上的具体处理者对象提交请求:
public class Client {
@Test
public void client() {
Leader generalManger = new GeneralManager(null, "刘备");
Leader manager = new Manager(generalManger, "诸葛亮");
Leader director = new Director(manager, "赵云");
director.handle(new Request("请假", "翡青", 32));
director.handle(new Request("涨薪", "zjf", 1500));
}
}
public class Request {
private String type;
private String content;
private int count;
public Request() {
}
public Request(String type, String content, int count) {
this.type = type;
this.content = content;
this.count = count;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
注: 非链表实现责任链 - 还可通过集合、数组等形式存储责任链, 很多项目中, 每个具体的Handler并不是开发团队定义的, 而是项目上线后又外部单位追加的, 此时使用链表方式定义chain of responsibility就很困难, 此时可选择使用集合存储.
小结
优缺点
- 降低耦合度: 客户提交一个请求, 请求沿链传递直至一个ConcreteHandler最终处理, 接收者和发送者都没有对方的明确信息, 便于接受者与发送者的解耦.
- 增强给对象指派职责的灵活性: 链中对象自己并不清楚链结构,他们仅保持一个后继者指针, 因此责任链可简化对象的相互连接, 且可以随时增加或修改处理请求的对象, 增强了给对象指派职责的灵活性.
- 缺陷: 不保证被接受: 既然一个请求没有明确的接收者, 那么就不能保证它能一定被正确处理, 即一个请求有可能到了链的末端也得不到处理, 或因为没有正确配置链顺序而得不到“正确”处理.
场景
- 有多个对象可以处理一类请求, 且哪个对象处理由运行时刻自动确定;
- 在不明确指定接收者的情况下, 向多个对象中提交同一个请求;
- 处理一个请求的对象集合被动态指定;
- Java异常机制: 一个
try
对应多个catch
; - Servlet:
Filter
链式处理; - Spring MVC : 拦截器链(详见: Spring MVC 实践);
- Java异常机制: 一个
相关模式
Composite(组合)模式: 这种情况下, 一个构件的父构件可作为它的后继者.
- by 翡青