责任链(Chain of Responsibility)模式 :责任链模式是对象的行为模式。使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系。将这些对象连成一条链,沿着这条链传递该请求,直到有一个对象处理它为止。责任链模式强调的是每一个对象及其对下家的引用来组成一条链,利用这种方式将发送者和接收者解耦。
责任链模式有两个角色:
抽象处理者(Handler)角色 :定义一个请求的接口。如果需要可以定义个一个方法用来设定和返回下家对象的引用。
具体处理者(ConcreteHandler)角色 :如果可以处理就处理请求,如果不能处理,就把请求传给下家,让下家处理。也就是说它处理自己能处理的请求且可以访问它的下家。
抽象处理者角色:
public abstract class Handler {
/**
* 持有后续的责任对象
*/
protected Handler successor;
/**
* 示意处理请求的方法,虽然这个示意方法没有传入参数
* 但实际是可以传入参数的,根据具体需要来选择是否传递参数
*/
public abstract void handleRequest();
public Handler getSuccessor(){
return successor;
}
public void setSuccessor(Handler successor){
this.successor = successor;
}
}
具体处理者角色:
public class ConcreteHandler extends Handler{
@Override
public void handleRequest() {
if(getSuccessor()!=null){
System.out.println("放过请求");
getSuccessor().handleRequest();
}else{
System.out.println("处理请求");
}
}
}
客户端类:
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
handler1.handleRequest();
}
}
可以看出,客户端创建了两个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,而第二个处理者对象没有下家。然后客户端将请求传递给第一个处理者对象。
使用场景
在OA系统中的请假审批流程,假如员工的直接上司为小组长,小组长的直接上司为项目经理,项目经理的直接上司为部门经理,部门经理的直接上司为总经理。若公司有如下规定:
请假时间为t,时间单位day,简写d:
t< 0.5d,小组长审批;
t>=0.5d,t<2,项目经理审批;
t>=2,t<5部门经理审批;
t>=5总经理审批;
用代码来描述:
小组长:
public class GroupLeader extends Handler {
@Override
public boolean approve(double day) {
if(day<0.5){
System.out.println("小组长通过了审批");
return true;
}else{
System.out.println("小组长传给了他的上司");
return getHandler().approve(day);
}
}
}
项目经理:
public class ProjectManager extends Handler {
@Override
public boolean approve(double day) {
if(day<2){
System.out.println("项目经理通过了审批");
return true;
}else{
System.out.println("项目经理传给了他的上司");
return getHandler().approve(day);
}
}
}
部门经理:
public class DepartmentManager extends Handler {
@Override
public boolean approve(double day) {
if(day<5){
System.out.println("部门经理通过了审批");
return true;
}else{
System.out.println("部门经理传给了他的上司");
return getHandler().approve(day);
}
}
}
总经理:
public class CEO extends Handler{
@Override
public boolean approve(double day) {
System.out.println("CEO审批通过");
return true;
}
}
客户端:
public class Client {
public static void main(String[] args) {
GroupLeader gl = new GroupLeader();
ProjectManager pm = new ProjectManager();
DepartmentManager dm = new DepartmentManager();
CEO ceo = new CEO();
gl.setHandler(pm);
pm.setHandler(dm);
dm.setHandler(ceo);
gl.approve(5);
}
}
运行结果:
小组长传给了他的上司
项目经理传给了他的上司
部门经理传给了他的上司
CEO审批通过
纯的与不纯的责任链模式
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,二是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又 把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。
责任链模式在现实中使用的很多,常见的就是OA系统中的工作流。 在java中的实际应用有Servlet中的过滤器(Filter),Struts2的拦截器(Interceptor)。Struts2本身在Servlet中也是以Filter的形式出现的,所以Struts2的结构图中,也可以明显看出Filter和Interceptor这两条链的存在。