1.定义
责任链模式属于行为型模式,顾名思义,为请求创建一个接收者对象的链,所有的对象都有可能接收到请求,请求沿着对象链传递,直到请求被处理,在这个过程中实现请求对象和接收对象的解耦,避免两者耦合在一起。
类比游戏中的副本关卡,挑战任务,或者日常生活中的等级考试,都可以理解为一个责任链。
比如软件应用中的web请求过滤器、拦截器实现,一个请求经过层层的过滤,对请求进行各种各样的处理,最后到达请求处理器,完成此次请求的处理。
责任链模式结构上有点类似于数据结构中的链表,将责任链上的对象通过next指针链接起来,然后沿着链向下调用,同时为了增加扩展性,将责任链上节点对象进行抽象,抽象出一个公共的抽象类。
责任链一般情况下是单向的链式结构,但是也可以根据需要实现成树形、环形、甚至其他的结构。
责任链角色总体上分为两类角色:
- 抽象处理者角色(Handler):定义一个处理请求的接口,包含一个抽象处理方法和一个后继对象next指针
- 具体处理者角色(Concrete Handler):实现抽象者的方法,实现自身的逻辑,判断是否能够处理本次请求,如果可以处理则处理,否则将请求转发给后继对象
UML:
图片来源:知乎
2.示例
以等级考试为例,对责任链模式进行简单实现,
张坤要想要进入某艺术学校,但需要进行考核,必须通过初试、复试,终试三个环节才能够进入艺术学校,于是张坤准备了三个节目来应对三场考核。
首先定义一个类表示节目:
/**
* @description: 节目
* @version: 1.0
*/
public class Item {
//节目名称
private String name;
//分数
private int score;
public Item(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
对考试进行抽象,其中应持有下一场考试的引用
/**
* @description: 抽象
* @version: 1.0
*/
public abstract class TalentShow {
protected TalentShow nextShow;
private Item item;
public TalentShow(Item item) {
this.item = item;
}
public TalentShow getNextShow() {
return nextShow;
}
public void setNextShow(TalentShow nextShow) {
this.nextShow = nextShow;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public abstract int upgrade();
}
分别对次考试进行实现,实现要求初试必须满足60分以上才能进入复试,复试成绩比如满足70分以上才能进入终试,终试分数需要达到80分以上,才算符合入学条件
/**
* @description: 初试
* @version: 1.0
*/
public class PrimaryShow extends TalentShow{
public PrimaryShow(Item item) {
super(item);
}
@Override
public int upgrade() {
if (this .getItem().getScore() >= 60){
System.out.println("分数大于60分,初试通过,进入下一轮复试");
if (this.nextShow != null){
this.nextShow.upgrade();
}
}
return this .getItem().getScore();
}
}
/**
* @description: 复试
* @version: 1.0
*/
public class SecondaryShow extends TalentShow{
public SecondaryShow(Item item) {
super(item);
}
@Override
public int upgrade() {
if (this.getItem().getScore() >= 70){
System.out.println("分数大于70分,复试通过,进入下一轮终试");
if (this.nextShow != null){
this.nextShow.upgrade();
}
}
return this.getItem().getScore();
}
}
/**
* @description: 终试
* @create by twotiger2tigersofast
* @datetime 2023/4/8 0:25
* @version: 1.0
*/
public class FinalShow extends TalentShow{
public FinalShow(Item item) {
super(item);
}
@Override
public int upgrade() {
if (this.getItem().getScore() >= 80){
System.out.println("分数大于80分,终试通过,Congratulations!");
if (this.nextShow != null){
this.nextShow.upgrade();
}
}
return this.getItem().getScore();
}
}
测试:
/**
* @description: test
* @version: 1.0
*/
public class Test {
public static void main(String[] args) {
//初始化节目
Item sing = new Item("唱",60);
Item jump = new Item("跳",70);
Item rap = new Item("Rap",80);
//初试、复试、终试
TalentShow primaryShow = new PrimaryShow(sing);
TalentShow secondaryShow = new SecondaryShow(jump);
TalentShow finalShow = new FinalShow(rap);
//关联
primaryShow.setNextShow(secondaryShow);
secondaryShow.setNextShow(finalShow);
primaryShow.upgrade();
}
}
input:
分数大于60分,初试通过,进入下一轮复试
分数大于70分,复试通过,进入下一轮终试
分数大于80分,终试通过,Congratulations!
3.总结
责任链的优点是将请求和处理分开,请求者可以不同知道是谁处理的,处理者也可以不必知道请求的全貌,责任链的实现是灵活的,可以根据实际需要加入更多的扩展设计,比如将责任链对象实现配置化,设置优先级,比如gateway中的拦截器配置,spring中过滤器的getOrder。责任链的缺点就是如果责任链太长,会影响请求对象的处理时长,并且会增加调试的复杂性。