定义
职责链( Chain of Responsibility )模式也被叫做责任链模式,在《设计模式》属于行为型模式,是一个请求有多个对象来处理,这些对象是一条链,但具体由哪个对象来处理,根据条件判断来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。责任链模式将请求和处理分离开来,进行解耦。
UML类图
具体角色
1、抽象处理者( Handler )角色:定义一个处理请求的抽象类。如果需要,可以定义一个方法以设定和返回对下家的引用。
2、具体处理者( ConcreteHandler ) 角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
举个例子
很常见的一个场景:请假。假定请假3天以内,由项目经理直接审批;3-5天,由部门经理审批通过;大于5天,则由总经理通过。
如果把上面的场景应用到责任链模式中去,项目经理、部门经理、总经理就是一个个具体的责任人,他们可以对请求做出处理,但是他们也只能在自己的权限范围内处理该请求。
编写代码
抽象处理类:
/**
* 抽象处理者
*/
public static abstract class Handler {
private Handler nextHandler;
// 当前领导能审批通过的最多天数
public int maxDay;
protected Handler(int maxDay) {
this.maxDay = maxDay;
}
//设置责任链中下一个处理请求的对象
public void setNextHandler(Handler handler) {
nextHandler = handler;
}
protected void handleRequest(int day) {
if (day <= maxDay) {
reply(day);
} else {
if (nextHandler != null) {
//审批权限不够,继续上报
nextHandler.handleRequest(day);
} else {
System.out.println("没有更高的领导审批了");
}
}
}
protected abstract void reply(int day);
}
具体处理者
项目经理
/**
* 项目经理
*/
class ProjectManager extends Handler {
public ProjectManager(int day) {
super(day);
}
@Override
protected void reply(int day) {
LogUtil.d(day + "天请假,项目经理直接审批通过");
}
}
部门经理
/**
* 部门经理
*/
class DepartmentManager extends Handler {
public DepartmentManager(int day) {
super(day);
}
@Override
protected void reply(int day) {
LogUtil.d(day + "天请假,部门经理审批通过");
}
}
总经理
/**
* 总经理
*/
class GeneralManager extends Handler {
public GeneralManager(int day) {
super(day);
}
@Override
protected void reply(int day) {
LogUtil.d(day + "天请假,总经理审批通过");
}
}
测试
Handler projectManager = new ProjectManager(3);
Handler departmentManager = new DepartmentManager(5);
Handler generalManager = new GeneralManager(15);
//创建职责链
projectManager.setNextHandler(departmentManager);
departmentManager.setNextHandler(generalManager);
//发起一次请求
projectManager.handleRequest(10);
结果:
10天请假,总经理审批通过
总结
应用场景
在实际软件开发中,如果遇到有多个对象可以处理同一请求时可以考虑使用职责链模式,最常见的例子包括在 Java Web 应用开发中创建一个过滤器(Filter)链来对请求数据进行过滤(中文字符乱码的处理)、在工作流系统中实现公文的分级审批、在Struts应用中添加不同的拦截器(常用的有类型转化、异常处理,数据校验…)以增强Struts2的功能等。
优点
- 降低耦合度,使请求的发送者和接收者解耦,便于灵活的、可插拔的定义请求处理过程;
- 简化、封装了请求的处理过程,并且这个过程对客户端而言是透明的,以便于动态地重新组织链以及分配责任,增强请求处理的灵活性;
- 可以从职责链任何一个节点开始,也可以随时改变内部的请求处理规则,每个请求处理者都可以去动态地指定他的继任者;
- 职责链可简化对象间的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用;
- 增加新的请求处理类很方便。
缺点
- 不能保证请求一定被接收。既然一个请求没有明确的接收者,那么就不能保证它一定会被处理;
- 该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理;
- 系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。