设计模式之责任链模式

简介

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

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

为什么用责任链

按照简介,可以用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方法指定下一个执行对象,只需要按顺序放入列表中即可,因为链表已经按顺序执行了,代码变得很简洁。

相关推荐
zaim112 分钟前
计算机的错误计算(二百二十六)
java·python·c#·c·错数·mpmath
小江的记录本20 分钟前
【RabbitMQ】RabbitMQ核心知识体系全解(5大核心模块:Exchange类型、消息确认机制、死信队列、延迟队列、镜像队列)
java·前端·分布式·后端·spring·rabbitmq·mvc
!停26 分钟前
C++入门—内存管理
java·jvm·c++
海参崴-29 分钟前
C语言与C++语言发展历史详解
java·c语言·c++
无尽的罚坐人生33 分钟前
hot 100 146. LRU 缓存
java·开发语言·缓存
好家伙VCC33 分钟前
**发散创新:基于算子融合的深度学习推理优化实战**在现代AI部署场景
java·人工智能·python·深度学习
wd5i8kA8i37 分钟前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
java·开发语言·php
却话巴山夜雨时i40 分钟前
Java大厂面试:从Spring Boot到微服务的深度剖析
java·spring boot·spring cloud·微服务·分布式事务·大厂面试
希望永不加班1 小时前
SpringBoot 缓存注解:@Cacheable/@CacheEvict 使用
java·spring boot·spring·缓存·mybatis
KhalilRuan1 小时前
HybridCLR的底层原理
java·开发语言