定义
什么是责任链模式?生活中我们经常遇到这样的问题,比如请假审批需要层层上报处理、遇到问题各个部门甩赖扯皮,像这种,在事情没有被处理之前,会经过一系列阶段,类似于“踢皮球”似的。同样地,当一个请求到达时,在程序无法直接决定由哪个对象负责处理时,客户的请求就会形成一种链式传递,在链上的各个处理对象如果无法直接决定是否由其处理时,就会将请求再传递至下一个链对象,直到请求被处理或者被丢弃等等。这种处理链我们形象称其为“责任链”。
责任链模式的定义是:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
使用实例
举个例子,初级、中级、高级开发工程师分别处理问题的能力不同,我们假设初级工程师只能处理难度级别为 1 的问题,中级工程师能处理难度为 1、2 的问题,高级工程师能处理难度级别为 1、2、3 的问题,另外我们有一个 Request 请求代表要处理的请求,内部包含一个难度级别和要请求的内容,我们先来看下类图的设计:
首先我们先定义一个请求接口:
interface IRequest {
// 获取请求级别
int getRequestLevel();
// 获取要请求的内容
String getRequest();
}
该接口包括一个难度级别和要请求的内容,这就是我们需要链式处理的请求,链上的处理对象根据请求难度级别获取请求内容选择是否进行处理,接下来是 IRequest 的实现类:
public class Request implements IRequest {
/**
* 难度级别1--初级工程师解决
* 难度级别2--中级工程师解决
* 难度级别3--高级工程师解决
*/
private int level;
// 要请求的内容或要解决的问题
private String request = "";
Request(int _level, String _request) {
this.level = _level;
switch (this.level) {
case 1:
this.request = "难度级别为1的请求是:" + _request;
break;
case 2:
this.request = "难度级别为2的请求是:" + _request;
break;
case 3:
this.request = "难度级别为3的请求是:" + _request;
break;
}
}
@Override
public int getRequestLevel() {
return this.level;
}
@Override
public String getRequest() {
return this.request;
}
}
实现类比较简单,类中的难度级别和请求内容从构造中传入,接下来是我们的核心类 Handler 抽象类:
public abstract class Handler {
final static int Difficulty_LEVEL_1_REQUEST = 1; // 难度级别为1
final static int Difficulty_LEVEL_2_REQUEST = 2; // 难度级别为2
final static int Difficulty_LEVEL_3_REQUEST = 3; // 难度级别为3
// 能处理的级别
private int level = 0;
// 责任传递,下一个责任人是谁
private Handler nextHandler;
// 每个类都要说明一下自己能处理哪些请求
Handler(int level) {
this.level = level;
}
// 负责Request的请求处理,final关键字声明不允许被子类覆盖
final void HandleMessage(IRequest request) {
// 如果请求级别小于可以处理的级别就直接处理,比如:高级工程师也可以处理难度级别为1的请求
if (request.getRequestLevel() <= this.level) {
this.response(request);
} else {
if (this.nextHandler != null) { // 有后续环节,请求传递
this.nextHandler.HandleMessage(request);
} else { // 无后续环节了,按照不同意处理
System.out.println("--------难度级别为" + request.getRequestLevel() + "的请求-------");
System.out.println("---抱歉,没有工程师可以处理---\n");
}
}
}
/*
* 如果不属于你处理的请求,你应该让请求路由到下一个环节的责任人
*/
void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 有请示那当然要回应
protected abstract void response(IRequest request);
}
Handler 类是链中对象的抽象类,链上的所有的责任对象都需要继承该对象,我们定义 HandleMessage 方法来进行请求的链式处理,可以看到:如果请求的难度级别不高于链对象可处理的难度级别时,由链对象直接负责处理,也就实现了前面讲到的高级工程师也可以处理难度级别为1的初级问题;如果请求难度级别过高超出可处理级别则请求继续向下传递,直至没有责任人可以处理为止,这就是责任链模式的核心。最后是 Handler 类的三个具体实现类,分别代表三个责任人对象:初级工程师、中级工程师及高级工程师,来看下怎么写的:
// 初级难度的责任人
class Primary extends Handler {
// 初级工程师可以处理难度等级为1的请求
Primary() {
super(Handler.Difficulty_LEVEL_1_REQUEST);
}
// 处理结果
@Override
protected void response(IRequest request) {
System.out.println("--------难度级别为1的请求-------");
System.out.println(request.getRequest());
System.out.println("初级工程师处理结果: 已处理\n");
}
}
class Middle extends Handler {
// 中级工程师可以处理难度等级为2的请求
Middle() {
super(Handler.Difficulty_LEVEL_2_REQUEST);
}
// 处理结果
@Override
protected void response(IRequest request) {
System.out.println("--------难度级别为2的请求-------");
System.out.println(request.getRequest());
System.out.println("中级工程师处理结果: 已处理\n");
}
}
class Senior extends Handler {
// 高级工程师可以处理难度级别为3的请求
Senior() {
super(Handler.Difficulty_LEVEL_3_REQUEST);
}
// 处理结果
@Override
protected void response(IRequest request) {
System.out.println("--------难度级别为3的请求-------");
System.out.println(request.getRequest());
System.out.println("高级工程师处理结果: 已处理\n");
}
}
这里,我们定义四个难度级别不同的请求,请求进入处理链后,各个责任对象就会根据难度级别选择处理,直至不能处理为止,测试结果输出如下:
--------难度级别为1的请求-------
难度级别为1的请求是:1+1=?
初级工程师处理结果: 已处理
--------难度级别为2的请求-------
难度级别为2的请求是:3*4=?
中级工程师处理结果: 已处理
--------难度级别为3的请求-------
难度级别为3的请求是:87834*765=?
高级工程师处理结果: 已处理
--------难度级别为4的请求-------
---抱歉,没有工程师可以处理---
可以看到,对于难度级别不同的请求,责任链上各个对象可以根据难度级别自行处理,对于不能处理的级别,也可以按照预期正常响应,责任链模式的魅力就在于此:_客户端不需要关心请求被谁处理,链上的各个责任人会根据预先设定的链的顺序依次处理,直至不能处理为止。_
组成角色
通过上面的实例,想必我们已经了解了什么是责任链模式,责任链模式的通用类图如下:
责任链模式的核心就是 Handler 链抽象对象,该对象包含一个指向下一个链对象的私有属性,“链”是责任链的核心,就是使用该属性进行链式调用实现的。责任链模式的包含的角色如下:
- 请求者(Client):Client 角色就是向链发送请求的角色,在上面的例子中,Main 函数扮演这个角色;
- 责任人的抽象类角色(Handler):Handler 角色是模式的核心,Handler 知道下一个责任人是谁,并根据责任人的处理能力选择是否将请求转发至下一个责任人。上面例子中,由 Handler 类扮演该角色;
- 具体责任人对象(ConcreteHandler):该角色是具体处理请求的对象,上面例子中,由 Primary、Middle、Senior 类扮演。
总结
本节介绍了责任链模式的概念、示例,责任链模式很好的降低了请求者和处理者的耦合度,弱化了前后关系,使得请求者不必关心请求真正是被哪个环节的哪个责任人处理,另外责任链模式下,链的调用顺序也是可控的,这也很好的实现了有序性。
责任人链模式的链式调用,有个非常明显的缺点就是:每个请求可能都是从头到尾走一遍,特别是调用链比较长时,这就加剧了系统的响应时间及导致调试的复杂性。