Java设计模式之责任链模式的示例详解

 更新时间:2022年11月03日 10:06:01   作者:Potato_土豆  
责任链模式是将链中的每一个节点看做是一个对象,每个节点处理的请求均不相同,且内部自动维护下一个节点对象,当一个请求从链式的首段发出时,会沿着链的路径依次传递给每一个节点对象。本文将通过示例和大家详细聊聊责任链模式,需要的可以参考一下

责任链模式是将链中的每一个节点看做是一个对象,每个节点处理的请求均不相同,且内部自动维护下一个节点对象,当一个请求从链式的首段发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求位置,属于行为模式。

这里需要注意的是每个节点都能对对象进行一定的处理(也可以不处理),处理完成之后节点再进行判断还要进行后续处理还是说传递给下一个节点。

应用场景

首先举一个日常的例子,比如我们申请开发票,首先我们要写好报销单,首先要你的部门领导审批,部门领导审批不通过直接打回,审批通过再由公司的总经理审批这里审批通过才算成审批完成。这种情况就很适合使用责任链模式。

总结一下责任链主要适用一下几种情况:

  • 多个对象可以处理同一个请求,但是具体由那个对象处理完成则在运行时决定。
  • 不明确指定接收者的情况下,向多个对象中的一个提交一个请求

可以看一下责任链模式的通用UML类图:

通过类图可以看到总共包含以下角色:

  • 抽象处理者:主要是定义处理请求的方法以及维护下一个处理结点的对象的引用
  • 具体处理者:处理的具体实现

责任链的精髓在于将很多处理节点行成个链式结构,并允许结点自身决定是否进行处理或者转发。

实际代码案例

下面举一个我们在开发时经常会遇到的一种情况:登录 比如我们开发一个管理系统在登录的时候往往我们会先判断客户端传递的账号及密码是否为空但凡有一个是空肯定是不能继续往下走的,然后就是根据用户账号密码拿到用户的所有信息,如果能拿到继续周下一步,拿不到则是报错提示用户不存在,到下一步又会判断当前用户的权限。

无模式情况下的代码

private String login(String username,String password) {
    if(username == null || password == null) {
        return "账户或者密码为null";
    }
    User user = queryUserInfo(username, password);
    if(user == null) {
        return "找不到用户";
    }
    if(!Objects.equals(user.getRoleName(), "超管")){
        return "没有权限";
    }
    return "登录成功";

}

private User queryUserInfo(String username,String password){
    if(Objects.equals(username, "土豆") && Objects.equals(password, "666666")) {
        return new User(username,password,"超管");
    }else if(Objects.equals(username, "土豆2号") && Objects.equals(password, "666666")){
        return new User(username,password,"普通员工");
    }
    return null;
}

发现判断代码都冗余在一个方法里面,后续改动修改都需要修改中这个方法不满足开闭原则。

采用责任链模式优化代码

首先创建抽象类规定抽象方法以及维护下一个节点

public abstract class Handler {
    protected Handler next;

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

    public abstract void doHandler(User user);
}

然后就是创建多个实现逻辑的节点对象:

public class ValidatedHandler extends Handler {
    @Override
    public void doHandler(User user) {
        if(user.getUsername() == null || user.getPassword() == null) {
            System.out.println("账户或者密码为null");
        }else{
            this.next.doHandler(user);
        }
    }
}
public class UserHandler extends Handler{
    @Override
    public void doHandler(User user) {
        queryUserInfo(user);
        if(user.getRoleName() == null){
            System.out.println("没有找到用户");
        }else{
            this.next.doHandler(user);
        }
    }
    private static void queryUserInfo(User user){
        if(Objects.equals(user.getUsername(), "土豆") && Objects.equals(user.getPassword(), "666666")) {
            user.setRoleName("超管");
        }else if(Objects.equals(user.getUsername(), "土豆2号") && Objects.equals(user.getPassword(), "666666")){
            user.setRoleName("普通员工");
        }
    }
}
public class AuthHandler extends Handler{
    @Override
    public void doHandler(User user) {
        if(!Objects.equals(user.getRoleName(), "超管")){
            System.out.println("没有权限");
        }
        System.out.println("登入成功");
    }
}

最后调用:

public static void main(String[] args) {
    User user = new User("土豆","666666");
    Handler validatedHandler = new ValidatedHandler();
    Handler userHandler = new UserHandler();
    Handler authHandler = new AuthHandler();
    validatedHandler.setNext(userHandler);
    userHandler.setNext(authHandler);
    validatedHandler.doHandler(user);

}

可以看一下UML类图:

采用建造者+责任链模式优化代码

上述的代码发现维护链表的操作在用户调用的那一层,链表的组装过于复杂,这个时候我们可以使用建造者模式, 自动维护链表的组装,调用者只需要指定链表的顺序即可 主要修改Handler内代码:

public abstract class Handler {
    protected Handler next;

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

    public abstract void doHandler(User user);

    public static class Builder {
        private Handler head;
        private Handler tail;

        public Builder addHandler(Handler handler) {
            if(this.head == null){
                this.head = this.tail = handler;
                return this;
            }
            this.tail.setNext(handler);
            this.tail = handler;
            return this;
        }

        public Handler build() {
            return this.head;
        }
    }
}
Handler.Builder builder = new Handler.Builder();
builder.addHandler(new ValidatedHandler())
        .addHandler(new UserHandler())
        .addHandler(new AuthHandler());
builder.build().doHandler(user);

可发现调用者只需要关心链表顺序写入就好

责任链模式优缺点

优点:

  • 请求与处理解耦
  • 处理者只需要关心自己的处理逻辑即可,如果不是自己的直接转发
  • 具有链式传递功能,请求者不需要关系链路结构等待结果就好
  • 易于维护,可以很灵活的修改链路的结构新增或者删除,符合开闭原则

缺点:

  • 会出现循环引用的情况
  • 责任链太长会影响性能

到此这篇关于Java设计模式之责任链模式的示例详解的文章就介绍到这了,更多相关Java责任链模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java详细讲解异常Exception的处理

    Java详细讲解异常Exception的处理

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等
    2022-06-06
  • SparkSQL使用IDEA快速入门DataFrame与DataSet的完美教程

    SparkSQL使用IDEA快速入门DataFrame与DataSet的完美教程

    本文给大家介绍使用idea开发Spark SQL 的详细过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-08-08
  • 设计模式在Spring框架中的应用汇总

    设计模式在Spring框架中的应用汇总

    这篇文章主要介绍了设计模式在Spring框架中的应用汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • 详解java关于对象的比较

    详解java关于对象的比较

    这篇文章主要为大家介绍了java关于对象的比较,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • spring中@Autowire和@Resource的区别在哪里(推荐)

    spring中@Autowire和@Resource的区别在哪里(推荐)

    这篇文章主要介绍了spring中@Autowire和@Resource的区别在哪里?本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • Springboot整合xxl-job实现动态传参

    Springboot整合xxl-job实现动态传参

    XXL-JOB是一个分布式任务调度平台,本文主要介绍了Springboot整合xxl-job实现动态传参,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • 使用maven构建java9 service实例详解

    使用maven构建java9 service实例详解

    本篇文章主要介绍了使用maven构建java9 service实例详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • JAVA中阻止类的继承(官方和非官方)

    JAVA中阻止类的继承(官方和非官方)

    在面向对象的理论中, 有一些方案要求你用一个办法来声明一个不可继承的类。一般而言,如果类提供的功能不应该被改变,或者更恰当的说,是被覆盖(override)的时候才会出现这种情况。在这篇文章里,我讨论在JAVA语言中的实现办法--官方和非官方的办法
    2014-01-01
  • java的接口解耦方式

    java的接口解耦方式

    这篇文章主要介绍了java的接口解耦方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java8中关于Function.identity()的使用

    Java8中关于Function.identity()的使用

    这篇文章主要介绍了Java8中关于Function.identity()的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05

最新评论