文章目录
1. 引入
责任链模式的思想其实广泛的存在于生活中各个隐秘的角落中,例如以各种维权事件来进行说明。假设Forlogen通过不懈努力的加班,终于攒够了一套小房子的首付,他开开心心的去售楼处交了首付。经过了很长时间的等待,售楼处通知Forlogen可以交房了,于是他满心期待的去验房。但当他进入自己的房子后发现了各种各样的问题,完全达不到交房的标准,于是他像很多的业主一样准备开始了维权之路。首先他来到了售楼处:
Forlogen:你们这种质量的房子都可以交房吗?那我们当大傻子呢?
置业顾问:先生您好,我们的房子都已经通过了政府的验收流程,如果您有疑问,可以去找我们的领导哦,我这边没有权利管哦!
于是Forlogen又大费周折终于见到了一直"出差"的领导。
Forlogen:房子的问题你们准备如何解决呢?
领导:先生是这样,我们这边肯定是按照正常的流程走过的,所以我们认为房子是完全可以通过验收的,至于您这里所提出的问题,我们不认为是质量问题,就是一些小瑕疵。如果您坚持认为房子质量有问题,可以找第三方或是到政府部门投诉我们,我们都是不怕的哦!
Forlogen被逼无奈,首先找到了住建局:
领导:你这个问题不在我们的责任范围内,建议你去房管局问一下。
没办法,Forlogen只好来到了房管局询问情况:
领导:你这个问题也不在我们的责任范围内,你可以去市局问一下。
于是,Forlogen驱车几百里来到了市局,结果市局的领导说:你这个问题就是开发商的问题呀,我们这边没有办法处理,建议你还是直接去找开发商吧
Forlogen:????WHAT Fxxx…
类似的场景在生活中经常可见,只要有人的地方就会有责任链思想的体现。说的简单一点,责任链就是一个推诿扯皮的过程,最后可能会有某个对象能够解决客户的问题。
2. 概念
责任链(Chain of Responsibility)的定义理解可以从关键字入手:
- 责任:即每个相关对象处理某件事情的能力和义务,如果是它职责范围内就应该解决,否则无法处理
- 链:所有的相关对象构成了一个链的形式,如果当前对象无法处理,就将它转交给下一个对象处理
因此,责任链可以定义为:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
责任链模式的通用类图如下所示:
其中主要包含三类角色:
- Handler:抽象处理者,它定义了下面具体处理者都应该遵循的一些规范,包含抽象处理方法和一个后继连接
- ConcreteHandler:具体处理者,实现抽象处理者的处理方法,如果它可以处理就进行处理,否则交给链上的下一个处理者
- Client:客户,它需要构建责任链,并向链头的处理者提交具体的请求,至于请求的传递和处理过程由责任链完成
3. 案例
我们这里以生活中的一个案例看一下,使用责任链模式和不适用责任链模式有什么区别。假设你想要去外地办点事,那么就需要请假,如果不超过3天,那么直接找导师就行;如果不超过5天,那么可以找系主任请假;如果超过了7天,那么就需要找院领导请假。
首先看一下不使用责任链模式的实现方法,如下所示:
class Tutor {
public void handleRequest(int day) {
if (day <= 3) {
System.out.println("Tutor say go....");
} else {
System.out.println("no one can handle this request...");
}
}
}
class Director {
public void handleRequest(int day) {
if (day <= 5) {
System.out.println("Director say go....");
} else {
System.out.println("no one can handle this request...");
}
}
}
class Master {
public void handleRequest(int day) {
if (day <= 7) {
System.out.println("Master say go....");
} else {
System.out.println("no one can handle this request...");
}
}
}
public class OldClient {
@Test
public void test(){
Tutor t = new Tutor();
Director d = new Director();
Master m = new Master();
int days= 5;
if (days <= 3){
t.handleRequest(days);
} else if(days <=5){
d.handleRequest(days);
} else{
m.handleRequest(days);
}
}
}
此时Client需要知道根据请假的天数去找相应的领导,但这样的模式会存在以下问题:
- Client必须完全清楚每个领导的批假权限
- 一旦某个领导的批假权限发生了改变,或者增加、减少了某个领导,Client也需要及时的知道
这样的方式到了了Client和每个Handler之间具有很高的耦合性,不利于代码的扩展和维护。而如果使用责任链模式,Client只需要知道将请假请求交给谁,至于最终假被谁批了并不关心。如下所示:
abstract class Handler{
private Handler next;
public Handler getNext() {
return next;
}
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(int day);
}
class Tutor extends Handler{
@Override
public void handleRequest(int day) {
if (day <= 3){
System.out.println("Tutor say go....");
} else {
if (getNext() != null){
getNext().handleRequest(day);
} else {
System.out.println("no one can handle this request...");
}
}
}
}
class Director extends Handler{
@Override
public void handleRequest(int day) {
if (day <= 5){
System.out.println("Director say go....");
} else {
if (getNext() != null){
getNext().handleRequest(day);
} else {
System.out.println("no one can handle this request...");
}
}
}
}
class Master extends Handler{
@Override
public void handleRequest(int day) {
if (day <= 7){
System.out.println("Master say go....");
} else {
if (getNext() != null){
getNext().handleRequest(day);
} else {
System.out.println("no one can handle this request...");
}
}
}
}
public class Client {
@Test
public void test(){
Handler h1 = new Tutor();
Handler h2 = new Director();
Handler h3 = new Master();
h1.setNext(h2);
h2.setNext(h3);
h1.handleRequest(6); // Master say go....
h1.handleRequest(2); // Tutor say go....
h1.handleRequest(4); // Director say go....
h1.handleRequest(100); // no one can handle this request...
}
}
4. 总结
责任链模式作为行为型模式的一种,它具有如下的优点:
- 降低耦合度,增强了代码的可扩展性和健壮性
- 增强了给对象指派职责的灵活性
- 简化了对象之间的链接
- 责任分担
但是它同样具有某些缺点,如下所示:
- 不能保证请求一定会被链上的对象所处理成功
- 如果链很长,那么效率将较低
- 责任链的构建依赖于Client,一定程度上增加了Client的复杂性
5. 应用
关于责任链模式在其他框架的应用,可以了解责任链模式实现的三种方式。