zoukankan      html  css  js  c++  java
  • 设计模式:责任链模式

    定义

    责任链模式将链中每一个节点都看作一个对象,每个节点处理的请求都不同,且内部自动维护下一个节点对象,当一个请求从链式的首段发出时,会沿着责任链预设的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止,属于行为型设计模式。

    使用场景:

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

    通用写法

    public abstract class Handler {
        protected Handler nextHandler;
    
        public void setNextHandler(Handler successor){
            this.nextHandler = successor;
        }
    
        public abstract void handleRequest(String request);
    
        public void handlerNext(String request){
            if(this.nextHandler != null){
                this.nextHandler.handleRequest(request);
            }
        }
    }
    
    public class HandlerA extends Handler{
        @Override
        public void handleRequest(String request) {
            System.out.println("handlerA:"+request);
            handlerNext(request);
        }
    }
    
    public class HandlerB extends Handler{
        @Override
        public void handleRequest(String request) {
            System.out.println("handlerB:"+request);
            handlerNext(request);
        }
    }
    

    测试:

        public static void main(String[] args) {
            Handler handlerA = new HandlerA();
            Handler handlerB = new HandlerB();
            handlerA.setNextHandler(handlerB);
            handlerA.handleRequest("hello chain");
        }
    

    image-20210104194256859

    时序图

    image-20210104194641731

    使用责任链模式解决实际问题

    业务代码

    下面用户登陆的伪代码,流程如下:非空判断-->用户存在性判断-->权限角色判断,包括我目前所在的公司的代码也是这样,不过比下面的代码长多了,好几百行,十分臃肿,我们可以考虑使用责任链模式,将所有步骤串联起来,可以使我们在具体编码时更加专注于某一个具体的业务逻辑处理。

    @Data
    public class Member {
        private String name;
        private String password;
        private String roleName;
    
        public Member(String name, String password) {
            this.name = name;
            this.password = password;
        }
    }
    
    public class MemberService {
        public void login(String name, String password){
            if(StringUtils.isEmpty(name) || StringUtils.isEmpty(password)){
                throw new RuntimeException("密码或账号为空,校验失败");
            }
    
            Member member = checkExist(name, password);
    
            if(member==null){
                throw new RuntimeException("用户不存在");
            }
    
            if(!"admin".equals(member.getRoleName())){
                throw new RuntimeException("权限不足,非法操作");
            }
            System.out.println("允许操作");
        }
    
        /**
         * 模拟查询数据库
         */
        private Member checkExist(String name, String password) {
            if("admin".equals(name) && "123456".equals(password)){
                Member member = new Member(name, password);
                member.setRoleName("admin");
                return member;
            }
            return null;
        }
    }
    

    改造成责任链模式

    public abstract class Handler {
        protected Handler chain;
    
        public void nextChain(Handler handler){
            this.chain = handler;
        }
    
        public abstract void doHandle(Member member);
    }
    
    public class ValidateHandler extends Handler{
        @Override
        public void doHandle(Member member) {
            if(StringUtils.isEmpty(member.getName()) || StringUtils.isEmpty(member.getPassword())){
                throw new RuntimeException("密码或账号为空,校验失败");
            }
            chain.doHandle(member);
        }
    }
    public class LoginHandler extends Handler{
        @Override
        public void doHandle(Member member) {
            if("admin".equals(member.getName()) && "123456".equals(member.getPassword())){
                member.setRoleName("admin");
                chain.doHandle(member);
            }else{
                throw new RuntimeException("用户不存在");
            }
        }
    }
    public class AuthHandler extends Handler{
        @Override
        public void doHandle(Member member) {
            if(!"admin".equals(member.getRoleName())){
                throw new RuntimeException("权限不足,非法操作");
            }
            System.out.println("允许操作");
        }
    }
    

    测试:

            Handler  validateHandler = new ValidateHandler();
            Handler loginHandler = new LoginHandler();
            Handler authHandler = new AuthHandler();
            validateHandler.nextChain(loginHandler);
            loginHandler.nextChain(authHandler);
    
            Member member = new Member("admin", "123456");
            validateHandler.doHandle(member);
    

    责任链模式结合建造者模式

    上述代码有一个问题,具体组装链式结构的角色是MemberService类,当链式结构较长时,MemberService的工作会异常繁琐,且代码臃肿,产生问题原因是链式结构组装非常复杂,而对于复杂对象的创建,我们很自然想到建造者模式,我们可以改造Handler代码。

    public abstract class Handler {
        protected Handler chain;
    
        public void nextChain(Handler handler){
            this.chain = handler;
        }
    
        public abstract void doHandle(Member member);
    
        public static class Builder{
            private Handler head;
            private Handler tail;
    
            public Builder addHandler(Handler handler){
                if(head==null){
                    this.head = this.tail = handler;
                    return this;
                }
                this.tail.nextChain(handler);
                this.tail = handler;
                return this;
            }
    
            public Handler build(){
                return this.head;
            }
        }
    }
    

    测试:

            Member member = new Member("admin", "123456");
            Handler ha = new Handler.Builder()
                    .addHandler(new ValidateHandler())
                    .addHandler(new LoginHandler())
                    .addHandler(new AuthHandler())
                    .build();
            ha.doHandle(member);
    

    这样的代码写法就比上一种要优美的多。

    责任链模式优缺点

    优点

    • 请求与处理解耦
    • 请求处理者只需要关注子的感兴趣的进行处理即可,对于不感兴趣的请求,直接转发给下一个节点对象
    • 具备链式传递处理请求功能,请求发送者不需要知晓链路结构,只需要等待请求处理结果即可。
    • 链路结构灵活,可以通过改变链路结构动态新增或删减责任。
    • 易于扩展新的请求处理类,符合开闭原则

    缺点

    • 责任链过长或处理时间过长,会影响整体性能
    • 如果节点对象存在循环引用,则会造成死循环
  • 相关阅读:
    二叉树的深度(剑指offer)
    平衡二叉树(剑指offer)
    平衡二叉树
    513. Find Bottom Left Tree Value(得到左下角的节点)(树的层次遍历)
    637. Average of Levels in Binary Tree(一棵树每层节点的平均数)(二叉树的层序遍历)
    145. Binary Tree Postorder Traversal(非递归实现二叉树的后序遍历)
    正则表达式式总结
    re模块
    生成器 生成器函数 列表推倒式 生成器表达式
    闭包,迭代器
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14232310.html
Copyright © 2011-2022 走看看