责任链模式(Chain of Responsibility Pattern)可以将多个对象组成一条职责链,然后按照它们在职责链上的顺序一个一个的找出到底应该谁来负责处理。
Trouble.java
package com.test.dp.ChainOfResponsibility.Sample;
//表示发生问题的类,它带有问题的编号
public class Trouble {
private int number; // 问题编号
public Trouble(int number) { // 生成问题
this.number = number;
}
public int getNumber() { // 获取问题编号
return number;
}
public String toString() { // 代表问题的字符串
return "[Trouble " + number + "]";
}
}
Support.java
package com.test.dp.ChainOfResponsibility.Sample;
//用来解决问题的类,他是职责链上对象
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) { // 解决问题的步骤
if (resolve(trouble)) {
done(trouble);
} else if (next != null) {
next.support(trouble);
} else {
fail(trouble);
}
}
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
package com.test.dp.ChainOfResponsibility.Sample;
//用来解决问题的具体类(永远“不处理问题”)
public class NoSupport extends Support {
public NoSupport(String name) {
super(name);
}
protected boolean resolve(Trouble trouble) { // 解决问题的方法
return false; // 自己什么也不处理
}
}
LimitSupport.java
package com.test.dp.ChainOfResponsibility.Sample;
//用来解决问题的具体类(仅解决编号小雨指定编号的问题)
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;
}
}
}
OddSupport.java
package com.test.dp.ChainOfResponsibility.Sample;
//用来解决问题的具体类(仅解决奇数编号的问题)
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
package com.test.dp.ChainOfResponsibility.Sample;
//用来解决问题的具体类(仅解决指定编号的问题)
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;
}
}
}
Main.java
package com.test.dp.ChainOfResponsibility.Sample;
//只做Suport的职责链,制造问题并测试程序行为
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 OddSupport("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 += 33) {
alice.support(new Trouble(i));
}
}
}
执行结果:
[Trouble 0] is resolved by [Bob].
[Trouble 33] is resolved by [Bob].
[Trouble 66] is resolved by [Bob].
[Trouble 99] is resolved by [Bob].
[Trouble 132] is resolved by [Diana].
[Trouble 165] is resolved by [Diana].
[Trouble 198] is resolved by [Diana].
[Trouble 231] is resolved by [Elmo].
[Trouble 264] is resolved by [Fred].
[Trouble 297] is resolved by [Elmo].
[Trouble 330] cannot be resolved.
[Trouble 363] is resolved by [Elmo].
[Trouble 396] cannot be resolved.
[Trouble 429] is resolved by [Charlie].
[Trouble 462] cannot be resolved.
[Trouble 495] is resolved by [Elmo].
总结:
应用实例:1、红楼梦中的"击鼓传花"。2、JS 中的事件冒泡。3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
优点:1、降低耦合度。它将请求的发送者和接收者解耦。2、简化了对象。使得对象不需要知道链的结构。3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。4、增加新的请求处理类很方便。
缺点:1、不能保证请求一定被接收。2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。3、可能不容易观察运行时的特征,有碍于除错。
使用场景:1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。3、可动态指定一组对象处理请求。
注意事项:在 JAVA WEB 中遇到很多应用。