设计模式之责任链

问题描述

第一、什么是责任链?
责任链模式是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。

在这里插入图片描述


第二、责任链的使用场景还是比较多的:
1、多条件流程判断:权限控制
2、ERP 系统流程审批:总经理、人事经理、项目经理
3、Java 过滤器的底层实现 Filter
如果不使用该设计模式,那么当需求有所改变时,就会使得代码臃肿或者难以维护,例如下面的例子。
假设现在有一个闯关游戏,进入下一关的条件是上一关的分数要高于XX:
游戏一共3个关卡
进入第二关需要第一关的游戏得分大于等于80
进入第三关需要第二关的游戏得分大于等于90
那么代码可以这样写:

/**
 * 第一关
 * @author shixiangcheng
 * @date 2022-08-24
 */
public class FirstPassHandler {
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        return 80;
    }
}
/**
 * 第二关
 * @author shixiangcheng
 * @date 2022-08-24
 */
public class SecondPassHandler {
    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        return 90;
    }
}
/**
 * 第三关
 * @author shixiangcheng
 * @date 2022-08-24
 */
public class ThirdPassHandler {
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");
        return 95;
    }
    /**
 * 测试类
 * @author shixiangcheng
 * @date 2022-08-24
 */
public class Test {
	public static void main(String[] args) {
	    FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关
	    SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关
	    ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关
	    int firstScore = firstPassHandler.handler();
	    //第一关的分数大于等于80则进入第二关
	    if(firstScore >= 80){
	        int secondScore = secondPassHandler.handler();
	        //第二关的分数大于等于90则进入第二关
	        if(secondScore >= 90){
	            thirdPassHandler.handler();
	        }
	    }
	}
}
}```
那么如果这个游戏有 100 关,我们的代码很可能就会写成这个样子:
```java
if(1关通过){
    // 第2关 游戏
    if(2关通过){
        // 第3关 游戏
        if(3关通过){
           // 第4关 游戏
            if(4关通过){
                // 第5关 游戏
                if(5关通过){
                    // 第6关 游戏
                    if(6关通过){
                        //...
                    }
                }
            } 
        }
    }
}

这种代码不仅冗余,并且当我们要将某两关进行调整时会对代码非常大的改动,这种操作的风险是很高的,因此,该写法非常糟糕。
第三、初步改造
如何解决这个问题,我们可以通过链表将每一关连接起来,形成责任链的方式,第一关通过后是第二关,第二关通过后是第三关…
这样客户端就不需要进行多重 if 的判断了:

public class FirstPassHandler {
	 /**
     * 第一关的下一关是 第二关
     */
    private SecondPassHandler secondPassHandler;
    public void setSecondPassHandler(SecondPassHandler secondPassHandler) {
        this.secondPassHandler = secondPassHandler;
    }
    //本关卡游戏得分
    private int play(){
        return 80;
    }
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        if(play() >= 80){
            //分数>=80 并且存在下一关才进入下一关
            if(this.secondPassHandler != null){
                return this.secondPassHandler.handler();
            }
        }
        return 80;
    }
}
public class SecondPassHandler {
	/**
     * 第二关的下一关是 第三关
     */
    private ThirdPassHandler thirdPassHandler;
    public void setThirdPassHandler(ThirdPassHandler thirdPassHandler) {
        this.thirdPassHandler = thirdPassHandler;
    }
    //本关卡游戏得分
    private int play(){
        return 90;
    }
    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        if(play() >= 90){
            //分数>=90 并且存在下一关才进入下一关
            if(this.thirdPassHandler != null){
                return this.thirdPassHandler.handler();
            }
        }
        return 90;
    }
}
public class ThirdPassHandler {
    //本关卡游戏得分
    private int play(){
        return 95;
    }
    /**
     * 这是最后一关,因此没有下一关
     */
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");
        return play();
    }
}
public class Test {
	public static void main(String[] args) {
        FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关
        SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关
        ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关
        firstPassHandler.setSecondPassHandler(secondPassHandler);//第一关的下一关是第二关
        secondPassHandler.setThirdPassHandler(thirdPassHandler);//第二关的下一关是第三关
        //说明:因为第三关是最后一关,因此没有下一关
        //开始调用第一关 每一个关卡是否进入下一关卡 在每个关卡中判断
        firstPassHandler.handler();
	}
}

缺点:每个关卡中都有下一关的成员变量并且是不一样的,形成链很不方便;代码的扩展性非常不好;
第四、责任链改造
既然每个关卡中都有下一关的成员变量并且是不一样的,那么我们可以在关卡上抽象出一个父类或者接口,然后每个具体的关卡去继承或者实现。有了思路,我们先来简单介绍一下责任链设计模式的基本组成:
抽象处理者(Handler)角色: 定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)角色: 实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)角色: 创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

在这里插入图片描述

public abstract class AbstractHandler {
    /**
     * 下一关用当前抽象类来接收
     */
    protected AbstractHandler next;
    public void setNext(AbstractHandler next) {
        this.next = next;
    }
    public abstract int handler();
}
public class FirstPassHandler extends AbstractHandler{
    private int play(){
        return 80;
    }
    @Override
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        int score = play();
        if(score >= 80){
            //分数>=80 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}
public class SecondPassHandler extends AbstractHandler{
    private int play(){
        return 90;
    }
    @Override
    public int handler(){
        System.out.println("第二关-->SecondPassHandler");

        int score = play();
        if(score >= 90){
            //分数>=90 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }

        return score;
    }
}
public class ThirdPassHandler extends AbstractHandler{
    private int play(){
        return 95;
    }
    @Override
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler");
        int score = play();
        if(score >= 95){
            //分数>=95 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}
public class Test {
	public static void main(String[] args) {
        FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关
        SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关
        ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关
        // 和上面没有更改的客户端代码相比,只有这里的set方法发生变化,其他都是一样的
        firstPassHandler.setNext(secondPassHandler);//第一关的下一关是第二关
        secondPassHandler.setNext(thirdPassHandler);//第二关的下一关是第三关
        //说明:因为第三关是最后一关,因此没有下一关
        //从第一个关卡开始
        firstPassHandler.handler();
	}
}

第五、结束语
设计模式有很多,责任链只是其中的一种,我觉得很有意思,非常值得一学。设计模式确实是一门艺术,仍需努力呀!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)