一、Backgroud 背景
- 什么是推卸责任?
- 坏的方面:去办事,被不同部门踢皮球
- 好的方面:当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负责处理时,就需要推卸责任。我们可以将多个对象组成一个职责链,然后按照它们在职责链上的顺序一个一个地找出谁来负责处理。
- 责任链模式:对于一个请求,能自己做就自己做,做不了就推卸给下一个人;下一个人能自己做就自己做,不能做再推卸给下一个人。
- 优点:
- Decouple the sender of a request from its receiver. 解耦请求的发送方及其接收方。
- 缺点:
- Latency. 延迟
二、责任链模式,Chain of Responsibility Pattern
When a client issues a request, the request propagates (传播) along the chain until a ConcreteHandler object takes responsibility for handling it.
当客户端发出请求时,请求沿链传播(传播),直到某个 ConcreteHandler 对象负责处理它。
2.1 Intent 意图
- Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. 通过为多个对象提供处理(同一)请求的机会的方式避免将请求的发送方与其接收方耦合:客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,故而解耦。
- Chain the receiving objects and pass the request along the chain until an object handles it. 链接接收对象并沿链传递请求直到某一个对象处理这个请求。
2.2 Applicability 适用情况
- More than one object may handle a request, and the handler isn’t known a priori(多个对象可以处理一个请求,并且处理程序先验已知的). The handler should be ascertained automatically(处理程序应自动确定)
- Want to issue a request to one of several objects without specifying the receiver explicitly(想要在不显式指定接收方的情况下向多个对象之一发出请求).
- The set of objects that can handle a request should be specified dynamically(应动态指定可以处理请求的对象集).
2.3 类图
- Handler
- Defines an interface for handling requests.
- (Optional) Implements the successor(后继者) link.
- ConcreteHandler
- Handles requests it is responsible for. q can access its successor. q If the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor.
- Client
- Initiates the request to a ConcreteHandler object on the chain.
2.4 责任链模式 Code
- Support:问题支持抽象类
java">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 void support(Trouble trouble) {
for (Support obj = this; true; obj = obj.next) {
if (obj.resolve(trouble)) {
obj.done(trouble);
break;
} else if (obj.next == null) {
obj.fail(trouble);
break;
}
}
}
public String toString() { // 显示字符串
return "[" + name + "]";
}
protected abstract boolean resolve(Trouble trouble); // 解决问题的方法
protected void done(Trouble trouble) { // 解决
System.out.println(trouble + " is resolved by " + this + ".");
}
protected void fail(Trouble trouble) { // 未解决
System.out.println(trouble + " cannot be resolved.");
}
}
- NoSupport
java">public class NoSupport extends Support {
public NoSupport(String name) {
super(name);
}
protected boolean resolve(Trouble trouble) { // 解决问题的方法
return false; // 自己什么也不处理
}
}
- OddSupport
java">public class OddSupport extends Support {
public OddSupport(String name) { // 构造函数
super(name);
}
protected boolean resolve(Trouble trouble) { // 解决问题的方法
if (trouble.getNumber() % 2 == 1) {
return true;
} else {
return false;
}
}
}
- SpecialSupport
java">public class SpecialSupport extends Support {
private int number; // 只能解决指定编号的问题
public SpecialSupport(String name, int number) { // 构造函数
super(name);
this.number = number;
}
protected boolean resolve(Trouble trouble) { // 解决问题的方法
if (trouble.getNumber() == number) {
return true;
} else {
return false;
}
}
}
- LimitSupport
java">public class LimitSupport extends Support {
private int limit; // 可以解决编号小于limit的问题
public LimitSupport(String name, int limit) { // 构造函数
super(name);
this.limit = limit;
}
protected boolean resolve(Trouble trouble) { // 解决问题的方法
if (trouble.getNumber() < limit) {
return true;
} else {
return false;
}
}
}
- Trouble
java">public class Trouble {
private int number; // 问题编号
public Trouble(int number) { // 生成问题
this.number = number;
}
public int getNumber() { // 获取问题编号
return number;
}
public String toString() { // 代表问题的字符串
return "[Trouble " + number + "]";
}
}
- Main
java">public class Main {
public static void main(String[] args) {
Support alice = new NoSupport("Alice_NoSupport");
Support bob = new LimitSupport("Bob_LimitSupport", 100); //只能处理100以下的数
Support charlie = new SpecialSupport("Charlie_SpecialSupport", 429); //只能处理429这一个数
Support diana = new LimitSupport("Diana_LimitSupport", 200); //只能处理200以下的数
Support elmo = new OddSupport("Elmo_OddSupport"); //只能处理奇数
Support fred = new LimitSupport("Fred_LimitSupport", 300); //只能处理三百以下的数
// 形成职责链
alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
// 制造各种问题
for (int i = 0; i < 500; i += 33) {
alice.support(new Trouble(i));
}
}
}
2.4 责任链模式优缺点
- 优点
- 降低耦合度
- 简化了对象,使得对象不需要知道链的结构
- 增强给对象指派职责的灵活性:通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
- 缺点
- 不能保证请求一定被接收
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用