推卸责任
1.模式介绍
当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负责处理时,就需要推卸责任,可将多个对象组成一条职责链,然后按照他们在职责链上的顺序一个一个找出到底应该谁来负责处理。
可以弱化请求方和处理方之间的关联关系,让双方各自成为都可以独立复用的组件,程序还可以应对其他需求,根据处理的对象而变化。
2.具体实例
Trouble类
/**
* @author Jay
* @date 2019/7/6 19:44
* @description
*/
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类
解决问题的抽象类,定义解决问题的流程和规范,整个责任链运行的流程,而具体的解决问题方案交给具体的子类去实现。
/**
* @author Jay
* @date 2019/7/6 19:49
* @description
*/
public abstract class Support {
/**
* 解决问题的实例的名字
*/
private String name;
/**
* 要推卸给的对象
*/
private Support next;
public Support(String name) { // 生成解决问题的实例
super();
this.name = name;
}
public Support setNext(Support next) { // 设置要推卸给的对象
this.next = next;
// 返回同一类型,可以进行链式调用
return next;
}
@Override
public String toString() { // 显示名字
return "Support [name=" + name + "]";
}
protected abstract boolean resolve(Trouble trouble);// 是否有解决问题的方法
protected void done(Trouble trouble) { // 解决问题
System.out.println(trouble + "被" + this + "解决");
}
protected void fail(Trouble trouble) { // 解决问题失败
System.out.println(trouble + "没有被" + this + "解决");
}
public final void support(Trouble trouble) { // 解决问题的步骤
if (resolve(trouble)) {
done(trouble);
} else if (next != null) {
next.support(trouble);
} else {
fail(trouble);
}
}
}
具体的处理类
public class LimitSupport extends Support {
/**
* 解决编号小于limit的问题
*/
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;
}else {
return false;
}
}
}
public class NoSupport extends Support {
public NoSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) { //解决问题的处理方法
// 自己不做处理,是一个永远不解决问题的类.
return false;
}
}
public class OddSupport extends Support {
public OddSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {// 解决问题的方案
if (trouble.getNumber() % 2 == 1) {
return true;
}
return false;
}
}
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;
}
}
测试类
/**
* @author Jay
* @date 2019/7/6 20:00
* @description
*/
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));
}
}
}
3.特点分析
弱化了发出请求人和处理请求的人之间的关系
Client向第一个ConcreteHandler角色发出请求,然后该请求会在职责链中传播,直到被处理.发出请求者并不知道哪个角色会具体处理此问题,只需负责放入职责链就可以,这样实现了解耦,增加了其作为可复用组件的独立性。
可以动态改变职责链
由于每个具体处理对象都是独立的,职责链可以随时拼接,随意组合,而且请求只是放入职责链中,并没有具体的确定某一实现类,因此可以根绝需求灵活的改变职责链。
专注自己的工作
每个ConcreteHandler只负责处理具体的业务,而不参与到流程之中,由父类统一负责,只需用到时放入责任链便可以,实现了可复用性,插拔式组件模式。
导致处理速度延迟
虽然提高了程序的灵活性,不过每次请求都需要从责任链中去寻找,这样会导致处理的速度稍慢,因此,对于处理速度要求较高,或者请求与处理者之间的关系是确定的,不使用该模式更好。