开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第27天,点击查看活动详情
责任链模式
我们首先看看什么是推卸责任。假设现在我们要去公司领取资料。首先我们向公司前台打听要去哪里领取资料,她告诉我们应该去“营业窗口”。然后等我们到了“营业窗口”后,又被告知应该去“售后部门”。等我们好不容易赶到了“售后部门”,又被告知应该去“资料中心”,因此最后我们又不得不赶往“资料中心"。像这样,在找到合适的办事人之前,我们被不断地踢给一个又一个人,这就是“推卸责任”。
“推卸责任”听起来有些贬义的意思,但是有时候也确实存在需要“推卸责任”的情况。例如,当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负责处理时,就需要推卸责任。这种情况下,我们可以考虑将多个对象组成一条职责链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责处理。
这种模式被称为Chain of Responsibility模式。
使用Chain of Responsibility模式可以弱化“请求方”和“处理方”之间的关联关系,让双方各自都成为可独立复用的组件。此外,程序还可以应对其他需求,如根据情况不同,负责处理的对象也会发生变化的这种需求。
当一个人被要求做什么事情时,如果他可以做就自己做,如果不能做就将“要求”转给另外一个人。下一个人如果可以自己处理,就自己做;如果也不能自己处理,就再转给另外一个人……这就是Chain of Responsibility模式。
事例程序
类一览表
| 名字 | 说明 |
|---|---|
| Trouble | 表示发生问题的类 |
| Support | 用来决解决问题的抽象类 |
| NoSupport | 解决问题的具体类 |
| LimitSupport | 解决问题的具体类 |
| OddSupport | 解决问题的具体类 |
| SpecialSupport | 解决问题的具体类 |
| Main | 测试 |
类图
代码
Trouble
- 发生问题的类,number表示问题的编号(解决问题通过问题编号解决)
- getNumber():的到问题编号
public class Trouble {
private int number;
public Trouble(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
@Override
public String toString() {
return "Trouble{" +
"number=" + number +
'}';
}
}
Support
- 解决问题的抽象类
- next表示下一个接手问题的对象,通过setNext指定
- resolve方法是需要子类去实现的抽象方法。如果resolve返回true,则表示问题已经被处理,如果返回false则表示问题还没有被处理(即需要被推卸给下一个对象)。
- (调用抽象方法resolve,模板模式)如果resolve方法返回false,则support方法会将问题转交给下一个对象。如果已经到达职责链中的最后一个对象,则表示没有人处理问题,将会显示出处理失败的相关信息。
public abstract class Support {
private String name;
private Support next;
public Support(String name) {
this.name = name;
}
public Support setNext(Support next) {
this.next = next;
return next;
}
public final void support(Trouble trouble) {
if (resolve(trouble)){
done(trouble);
}else if(next!=null){
next.support(trouble);
}else{
fail(trouble);
}
}
@Override
public String toString() {
return "Support{" +
"name='" + name + ''' +
'}';
}
protected abstract boolean resolve(Trouble trouble);
protected void done(Trouble trouble) {
System.out.println(trouble + "is resolve by" + this);
}
protected void fail(Trouble trouble) {
System.out.println(trouble + "can't be resolved");
}
}
Nosupport
- Support的子类
- resolve返回false表示无法解决
public class NoSupport extends Support{
public NoSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
return false;
}
}
LimitSupport
- 编号小于limit表示解决成功,可接具体的处理逻辑
public class LimitSupport extends Support {
private int limit;
public LimitSupport(String name, int limit) {
super(name);
this.limit = limit;
}
@Override
protected boolean resolve(Trouble trouble) {
if (trouble.getNumber() < limit) {
//具体的处理逻辑
return true;
}
return false;
}
}
OldSupport
- 解决编号位奇数的问题
public class OldSupport extends Support {
public OldSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
if (trouble.getNumber() % 2 == 1) {
return true;
}
return false;
}
}
SpecialSupport
- 解决指定编号的问题
public class SpecialSupport extends Support {
private int number;
public SpecialSupport(String name, int number) {
super(name);
this.number = number;
}
@Override
protected boolean resolve(Trouble trouble) {
if (trouble.getNumber() == number) {
return true;
}
return false;
}
}
Main
public class Main {
public static void main(String[] args) {
Support alice = new NoSupport("Alice");
Support bob = new LimitSupport("Bob", 100);
Support charlie = new SpecialSupport("Charlie", 429);
Support diana = new LimitSupport("Diana", 200);
Support elmo = new OldSupport("Elmo");
Support fred = new LimitSupport("Fred", 300);
alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
for (int i = 0; i < 500; i++) {
alice.support(new Trouble(i));
}
}
}
result:
Trouble{number=0}is resolve bySupport{name='Bob'}
Trouble{number=1}is resolve bySupport{name='Bob'}
Trouble{number=2}is resolve bySupport{name='Bob'}
Trouble{number=3}is resolve bySupport{name='Bob'}
Trouble{number=4}is resolve bySupport{name='Bob'}
Trouble{number=5}is resolve bySupport{name='Bob'}
............
............
............
Trouble{number=495}is resolve bySupport{name='Elmo'}
Trouble{number=496}can't be resolved
Trouble{number=497}is resolve bySupport{name='Elmo'}
Trouble{number=498}can't be resolved
Trouble{number=499}is resolve bySupport{name='Elmo'}
登场角色
-
Handler(处理者)
Handler 角色定义了处理请求的接口(API )。Handler 角色知道“下一个处理者”是谁,如果自己无法处理请求,它会将请求转给“下一个处理者”。当然,“下一个处理者”也是Handler角色。在示例程序中,由 support类扮演此角色。负责处理请求的是 support方法。
-
ConcreteHandler(具体的处理者)
ConcreteVisitor角色是处理请求的具体角色。在示例程序中,由NoSupport、LimitSupport,Oddsupport、 Specialsupport等各个类扮演此角色。
-
Client(请求者)
发送请求,Main