动机
- 在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能由一个接受者,如果显示指定,将比不可少的带来发送者和接受者的紧耦合。
- 如何使请求的发送者不需要指定具体的接受者?让请求的接受者自己在运行时决定来处理请求,从而使两者解耦。
模式定义
是多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
类图
要点总结
- Chain of Responsibility模式的应用场合在于“一个请求可能有多个接受者,但是最后真正的接受者只有一个”,这时候请求发送者与接受着的耦合可能出现“变化脆弱”的症状,职责链的目的就是将二者解耦,从而更好的应对变化。
- 应了Chain of Responsibility模式后,对象的职责分派将更具灵活性。我们可以在运行时动态添加/修改请求的处理职责。
- 如果请求传递到职责链的末尾仍得不到处理,应该有一个合理的缺省机制。这也是每一个接受对象的责任,而不是发出请求的对象的责任。
实例
项目组聚餐,经费申请,每级领导的审批的钱数不一样;我们申请的经费不确定是哪个领导批,申请请求在不同的领导直接流转,直到其中一个批准为止。
- 创建抽象处理类,类中包含下一个处理类的引用。
public abstract class AbstractHandler {
protected AbstractHandler nextHandler;
public void setNextHandler(AbstractHandler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract String handler(String user, double fee);
}
- 分别实现项目经理、部门经理、总经理的处理类
public class ProjectManager extends AbstractHandler {
@Override
public String handler(String user, double fee) {
String result = null;
if (fee < 500) {
result = "project ratify, user:" + user + ", fee:" + fee;
} else {
if (this.nextHandler != null) {
result = this.nextHandler.handler(user, fee);
}
}
return result;
}
}
public class DeptManager extends AbstractHandler {
@Override
public String handler(String user, double fee) {
String result = null;
if (fee < 1000) {
result = "Department ratify, user:" + user + ", fee:" + fee;
} else {
if (this.nextHandler != null) {
result = this.nextHandler.handler(user, fee);
}
}
return result;
}
}
public class GeneralManager extends AbstractHandler {
@Override
public String handler(String user, double fee) {
String result = null;
if (fee < 10000) {
result = "General ratify, user:" + user + ", fee:" + fee;
} else {
if (this.nextHandler != null) {
result = this.nextHandler.handler(user, fee);
}
}
return result;
}
}
- 客户使用类,自己组合调用的职责链,并向其中一个处理这发送请求。
public class Client {
public static void main(String[] args) {
AbstractHandler project = new ProjectManager();
AbstractHandler dept = new DeptManager();
AbstractHandler general = new GeneralManager();
project.setNextHandler(dept);
dept.setNextHandler(general);
System.out.println(project.handler("wx", 2000));
}
}