责任链模式
简介
GoF分类:行为型设计模式。
英文名:Chain of Responsibility。
管道模式:责任链模式的常用变种之一,纯的责任链模式在链上只会有一个处理器用于处理数据,而管道模式上多个处理器都会处理数据。
应用场景1:Netty、Spring MVC、Selvlet等组件或者框架的拦截器部分都应用了责任链模式。
应用场景2:当你的调用链太长,或者有异步代码嵌套太深,可以考虑用责任链模式优化代码。
示例1-递归调用
示例1:以下代码来源自《图解设计模式》中的示例,模拟的是问题处理过程。
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: Support
* @Description: 解决问题的抽象类
* @author: 王同学
* @date: 2023年5月8日 下午3:52:18
* @Copyright:
*/
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;
}
@Override
public String toString() {
return "[ "+this.name+" ]";
}
public final void support(Trouble trouble) { // 解决问题的步骤
if(resolve(trouble)) {
this.done(trouble);
}else if(this.next!=null) {
this.next.support(trouble);
}else {
this.fail(trouble);
}
}
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+"未被处理!");
}
}
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: NoSupport
* @Description: 一个什么都处理不了的处理方案
* @author: 王同学
* @date: 2023年5月8日 下午4:12:04
* @Copyright:
*/
public class NoSupport extends Support{
public NoSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
return false;
}
}
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: LimitSupport
* @Description: 解决小于limit的错误
* @author: 王同学
* @date: 2023年5月8日 下午4:13:16
* @Copyright:
*/
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()<this.limit) {
return true;
}else {
return false;
}
}
}
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: OddSupport
* @Description: 解决奇数编号的错误
* @author: 王同学
* @date: 2023年5月8日 下午4:16:27
* @Copyright:
*/
public class OddSupport extends Support{
public OddSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
if(trouble.getNumber()%2==1) {
return true;
}else {
return false;
}
}
}
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: SpecialSupport
* @Description: 解决指定编号的问题
* @author: 王同学
* @date: 2023年5月8日 下午4:17:58
* @Copyright:
*/
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()==this.number) {
return true;
}else {
return false;
}
}
}
package com.wwq.ChainResponsibility.tj.bean;
/**
*
* @ClassName: Trouble
* @Description: 需要处理的问题
* @author: 王同学
* @date: 2023年5月8日 下午4:01:05
* @Copyright:
*/
public class Trouble {
private int number; // 问题编号
public Trouble(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public String toString() {
return "[ "+this.number+" ]";
}
}
package com.wwq.ChainResponsibility.tj;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: Main
* @Description: 测试
* @author: 王同学
* @date: 2023年5月8日 下午2:15:18
* @Copyright:
*/
public class Main {
public static void main(String[] args) {
Support start = new NoSupport("start");
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);
// 形成责任链
start.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
for(int i=0;i<500;i++) { // 模拟解决问题
start.support(new Trouble(i));
}
}
}
示例2-循环调用
将示例1中的示例代码,改为使用循环而不是递归。
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.");
}
}
- 注意:有些博客的示例中,将改为循环理解为使用
List
等容器来存储调用链。其实改为循环的核心目的是减少调用栈的资源占用(方法栈不递归深入)。
示例3-管道模式
将示例2中的示例代码,改为管道模式。
package com.wwq.ChainResponsibility.tj3;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: Support
* @Description: 解决问题的抽象类
* @author: 王同学
* @date: 2023年5月8日 下午3:52:18
* @Copyright:
*/
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;
}
@Override
public String toString() {
return "[ "+this.name+" ]";
}
public final void support(Trouble trouble) { // 解决问题的步骤
int count = 0;
Support obj = this;
do {
if (obj.resolve(trouble)) {
obj.done(trouble);
count++;
}
obj=obj.next;
}while(obj.next != null);
if(count==0) {
obj.fail(trouble);
}
}
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+"未被处理!");
}
}
package com.wwq.ChainResponsibility.tj3;
import com.wwq.ChainResponsibility.tj.bean.Trouble;
/**
*
* @ClassName: Main
* @Description: 测试
* @author: 王同学
* @date: 2023年5月8日 下午2:15:18
* @Copyright:
*/
public class Main {
public static void main(String[] args) {
Support start = new NoSupport("start");
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);
// 形成责任链
start.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
start.support(new Trouble(3));
}
}