职责链模式

职责链模式(Chain of Responsibility Pattern):避免请求发送者与接受者耦合一起。把全部有可能接受请求的对象连接成一条链,并沿着这条链传递请求,知道有对象处理该请求为止。

假设有一个需求,当用户咨询客服时,需要根据用户的年龄提供不同的客服人员,先看一下传统的处理方式,下面是伪代码:

Handler 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class PersonRequestHandler {
private Person person;

public PersonRequestHandler(Person person) {
this.person = person;
}

public void handle() {
int age = this.person.getAge();
if (age < 5) {
handleForChild();
} else if (age < 23) {
handleForYouth();
} else if (age < 60) {
handleForAdult();
} else {
handleForOld();
}
}

private void handleForOld() {
LogUtils.i("doSomething For Old");
}

private void handleForAdult() {
LogUtils.i("doSomething For Adult");

}

private void handleForYouth() {
LogUtils.i("doSomething For Youth");

}

private void handleForChild() {
LogUtils.i("doSomething For Chile");
}
}

用这样的方式完全可以处理这个需求,但是只停留在完成需求这个阶段远远不够,这种方式有几个问题:

  • 如果需要更细分年龄段 Handler 类会变的异常庞大,不易阅读和维护
  • 所有的处理都放在该类中,违反了单一职责原则
  • 如果需要增删处理方式,就需要修改该类,又违反了开闭原则

职责链模式的出现解决了上述的几个问题,先来看职责链模式的结构图:

职责链模式

  • Handler(抽象处理者):一般设计为抽象类,定义一个请求接口,不同的具体处理者处理请求的方式不同。因为每个处理者的下家还是一个处理者,因此抽象处理者中定义了一个抽象处理者的对象,作为对下家的引用,通过该引用,就可以把所有处理者形成一条链

  • Concrete(具体处理者):抽象处理者的实现类,实现请求接口处理用户请求,处理请求前根据处理条件进行判断,看是否有能力处理,如果有就处理,没有则转发给下家

下面是利用职责链模式处理上面需求的伪代码:

Handler 类:

1
2
3
4
5
6
7
8
9
10
public abstract class Handler {

protected Handler successor;

public void setSuccessor(Handler successor) {
this.successor = successor;
}

public abstract void handleRequest(Person person);
}

ConcreteHandler 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Child
public class Child extends Handler {
@Override
public void handleRequest(Person person) {
if (person.getAge() < 5) {
LogUtils.i("doSomething For Child");
} else {
this.successor.handleRequest(person);
}
}
}

// Youth
public class Youth extends Handler {
@Override
public void handleRequest(Person person) {
if (person.getAge() < 23) {
LogUtils.i("doSomething For Youth");
} else {
this.successor.handleRequest(person);
}
}
}

// Adult
public class Adult extends Handler {
@Override
public void handleRequest(Person person) {
if (person.getAge() < 60) {
LogUtils.i("doSomething For Adult");
} else {
this.successor.handleRequest(person);
}
}
}

// Old
public class Old extends Handler {
@Override
public void handleRequest(Person person) {
LogUtils.i("doSomething For Old");
}
}

这种属于纯的职责链模式,ConcreteHandler 对象只能在处理和不处理两个行为中选择一个

如果是不纯的职责链模式是允许在处理请求时只处理一部分,然后继续往下家发送该请求;也可以全部处理完成后,再往下家发送;同时也允许该请求不被任何 ConCreteHandler 对象接收并处理

优点

  • 职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度

  • 在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责

  • 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,符合开闭原则

缺点

  • 职责链模式没有一个明确的接收者,所以请求就不能保证一定会被处理

  • 较长的职责链,处理请求涉及多个处理对象,给代码调试带来不便

  • 如果建链不当,很可能导致循环调用,引发系统死循环

适用场景

  • 一个请求可以被多个对象处理时,在运行时才能确定具体该由那个对象处理

  • 需要动态指定处理者时,客户端可以动态建链,可以动态改变处理者在链中的次序