设计模式之责任链模式

简介

责任链模 式是一种行为设计模式, 允许你将请求沿着处理者链(单向链表)进行发送。 收到请求后, 每个处理者根据自身条件对请求进行处理, ,如果处理不了则将其传递给链上的下个处理者,以此类推,直到有处理着能对请求进行处理返回,当到达处理者链的最后一个节点也不能处理该请求,则抛出异常。

可以用下图表示责任链设计模式:

为什么用责任链

按照简介,可以用if-else来代替:

java 复制代码
if(条件1){
	//doSomething
}else if(条件2){
	//doSomething
}else if(条件3){
	//doSomething
}else{
	//doSomething
}

当条件很多的时候,if-else就变得很多很长,看起来头疼,维护起来也头疼,代码耦合度很高,当需要新增或删除条件的时候,维护成本就很高。责任链的出现就是为了解耦。只需将请求放到处理者链上,处理者链对于请求会有各自的处理方式,更方便二次开发。

责任链结构

抽象处理者(Handler)角色 :定义一个处理请求的抽象方法,包含抽象处理方法和一个后继连接
具体处理者(Concrete Handler)角色 :实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程

代码实现

抽象处理者(Handler)角色

java 复制代码
public abstract class Handler {

    Handler next;

    /**
     * 使用Boolean类型而不用boolean是为了null这个值,当处理的结果是false时,
     * 但这个false是对业务有意义的,应该返回。但需要区分出是false还是找不到处理器,此时null就成了有意义的错误值
     * 用于区分是否找到对应的处理器
     * @param request 请求对象
     */
    public abstract Boolean execute(RequestDemo request);

    public void setNext(Handler next) {
        this.next = next;
    }
}

具体处理者(Concrete Handler)角色

处理者A

java 复制代码
public class ExecuteA extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
      	//判断是否由当前处理者处理
        if ("A".equals(request.getType())){
            System.out.println("A 处理");
            return true;
        }else if (next != null){
            //无法处理则传递给下一个处理者
            return next.execute(request);
        }else{
        	//当到达最后一个处理者(最后一个处理者的next为null)还不能处理时,抛出异常(或进行其他处理)
        	 throw new RuntimeException("can not find any execute");
        }
    }
}

处理者B

java 复制代码
public class ExecuteB extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
        //判断是否由当前处理者处理
        if ("B".equals(request.getType())){
            System.out.println("B 处理");
            return true;
        }else if (next != null){
            //无法处理则传递给下一个处理者
            return next.execute(request);
        }else{
        	//当到达最后一个处理者(最后一个处理者的next为null)还不能处理时,抛出异常(或进行其他处理)
        	 throw new RuntimeException("can not find any execute");
        }
    }
}

处理者C

java 复制代码
public class ExecuteC extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
    	//判断是否由当前处理者处理
        if ("C".equals(request.getType())){
            System.out.println("C 处理");
            return true;
        }else if (next != null){
            //无法处理则传递给下一个处理者
            return next.execute(request);
        }else{
        	//当到达最后一个处理者(最后一个处理者的next为null)还不能处理时,抛出异常(或进行其他处理)
        	 throw new RuntimeException("can not find any execute");
        }
    }
}

处理传递的对象(额外)

java 复制代码
public class RequestDemo {

    private String type;

    public RequestDemo(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

客户类(Client)角色

java 复制代码
public class NormMain {
    public static void main(String[] args) {
        ExecuteA executeA = new ExecuteA();
        ExecuteB executeB = new ExecuteB();
        ExecuteC executeC = new ExecuteC();

        //构建责任链,即构建处理的链表
        executeA.setNext(executeB);
        executeB.setNext(executeC);

        //构建需要处理对象
        RequestDemo requestDemo = new RequestDemo("C");

        //责任链的第一个节点开始调用,保证处理是层层往下的,不会忽略某个节点的处理器
        executeA.execute(requestDemo);
    }
}

优化版责任链模式

上面的责任链构建方式看起来有点冗余,可以优化一下。在抽象处理者里定义一个有序列表保存所有的处理者,当需要处理请求的时候,对列表进行遍历挑选合适的处理者即可。

抽象处理者(Handler)角色

java 复制代码
public abstract class Handler {

    Handler next;

    /**
     * 使用Boolean类型而不用boolean是为了null这个值,当处理的结果是false时,
     * 但这个false是对业务有意义的,应该返回。但需要区分出是false还是找不到处理器,此时null就成了有意义的错误值
     * 用于区分是否找到对应的处理器
     * @param request 请求对象
     */
    public abstract Boolean execute(RequestDemo request);

    public void setNext(Handler next) {
        this.next = next;
    }
}

执行链表对象:

java 复制代码
public class HandlerChain {

    private List<Handler> handlers = new ArrayList<>();

    public HandlerChain(List<Handler> handlers) {
        this.handlers = handlers;
    }

    public HandlerChain(Handler ...handler) {
        handlers.addAll(Arrays.asList(handler));
    }

    public void addHandler(Handler handler){
        handlers.add(handler);
    }

    public void addHandlers(Handler ...handler){
        handlers.addAll(Arrays.asList(handler));
    }

    public void addHandler(List<List> handler){
        this.handlers = handlers;
    }

    public boolean handleRequest(RequestDemo request) {
        if (handlers == null || handlers.size() == 0){
            throw new RuntimeException("can not find any execute");
        }
        for (Handler handler : handlers) {
            Boolean executeResult = handler.execute(request);
            if (executeResult != null){
                //找到对应的处理器,处理后应该返回
                return executeResult ;
            }
        }
        // 如果执行到这里,说明上面的return并没有执行,也就是找不到对应的处理器,此时该抛出异常
        throw new RuntimeException("can not find any execute");
    }
}

处理者A

java 复制代码
public class ExecuteA extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
        if ("A".equals(request.getType())){
            System.out.println("A 处理");
            return true;
        }
        return null;
    }
}

处理者B

java 复制代码
public class ExecuteB extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
        if ("B".equals(request.getType())){
            System.out.println("B 处理");
            return true;
        }
        return null;
    }
}

处理者C

java 复制代码
public class ExecuteC extends Handler {
    @Override
    public Boolean execute(RequestDemo request) {
        if ("C".equals(request.getType())){
            System.out.println("C 处理");
            return true;
        }
        return null;
    }
}

客户类(Client)角色

java 复制代码
public class ListHandlerMain {
    public static void main(String[] args) {
        RequestDemo requestDemo = new RequestDemo("C");
        HandlerChain handlerChain = new HandlerChain(new ExecuteA(),new ExecuteB(),new ExecuteC());
        handlerChain.handleRequest(requestDemo);
    }

优点:使用这种含列表方式的责任链的话,不需要调用抽象类的setNext方法指定下一个执行对象,只需要按顺序放入列表中即可,因为链表已经按顺序执行了,代码变得很简洁。

相关推荐
倔强的小石头_2 小时前
【C语言指南】函数指针深度解析
java·c语言·算法
kangkang-6 小时前
PC端基于SpringBoot架构控制无人机(三):系统架构设计
java·架构·无人机
界面开发小八哥7 小时前
「Java EE开发指南」如何用MyEclipse创建一个WEB项目?(三)
java·ide·java-ee·myeclipse
idolyXyz8 小时前
[java: Cleaner]-一文述之
java
一碗谦谦粉8 小时前
Maven 依赖调解的两大原则
java·maven
netyeaxi9 小时前
Java:使用spring-boot + mybatis如何打印SQL日志?
java·spring·mybatis
收破烂的小熊猫~9 小时前
《Java修仙传:从凡胎到码帝》第四章:设计模式破万法
java·开发语言·设计模式
猴哥源码9 小时前
基于Java+SpringBoot的动物领养平台
java·spring boot
老任与码9 小时前
Spring AI Alibaba(1)——基本使用
java·人工智能·后端·springaialibaba
小兵张健9 小时前
武汉拿下 23k offer 经历
java·面试·ai编程