美文网首页
责任链模式(Chain of Responsibility Pa

责任链模式(Chain of Responsibility Pa

作者: 吉他手_c156 | 来源:发表于2020-04-08 11:53 被阅读0次

    责任链模式的定义与特点

    定义:
    责任链模式(Chain Of Responsibility Pattern)是将链中每一个节点看做是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首段发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。
    注意:责任链模式也叫职责链模式。
    优点:
    1.解耦。请求发起者和请求响应者进行解耦,链的创建由使用者(客户端)创建。
    2.链路结构灵活。可以通过改变链路结构动态的新增或删减责任。
    3.易扩展。可以根据需要增加新的请求处理类,满足开闭原则。
    4.责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
    5.责任链简化了对象的连接。每个对象只保持一个指向其后继者的引用,不需要保持其他所有处理者的引用,这避免了使用众多的 if 或者 if...else 语句。
    缺点:
    1.责任链太长或者处理时间过长,会影响整体性能。
    2.如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。

    模式的角色

    1.抽象处理者(Hanlder)角色:定义一个处理请求的接口,持有下一个处理类的引用。
    2.具体处理者(Concrete Handler)角色:实现抽象处理者的方法,判断能否处理本次请求,否则将请求传给下一个处理者。
    3.客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

    责任链模式的实现

    1.创建抽象处理角色

    /**
     * 抽象处理角色:定义处理请求接口,持有下一个处理类的引用
     */
    public abstract class Handler {
    
        // 下一个处理类
        private Handler next;
    
        public void setNextHandler(Handler next){
            this.next = next;
        }
        public Handler getNextHanler(){
            return this.next;
        }
        // 处理请求抽象类
        public abstract void handlerRequest(String request);
    }
    

    2.分别创建具体处理角色A,B

    /**
     * 具体处理者角色A:实现抽象处理者的方法,判断是否又能里处理请求
     *                 否则将请求传递给下一个处理者
     */
    public class ConcreteHandlerA extends Handler {
        @Override
        public void handlerRequest(String request) {
            if("A".equals(request)){
                System.out.println("具体处理者 A 负责处理该请求");
            }else{
                // 如果处理不了,如果有下一个处理者,将请求传递个下一个处理者
                if(getNextHanler() != null){
                    getNextHanler().handlerRequest(request);
                }else{
                    System.out.println("没有人处理该请求了!");
                }
            }
        }
    }
    
    /**
     * 具体处理者角色B:实现抽象处理者的接口,判断是否能处理该请求
     *                  否则传递给下一个处理者
     */
    public class ConcreteHandlerB extends Handler{
        @Override
        public void handlerRequest(String request) {
            if("B".equals(request)){
                System.out.println("具体处理者 B 负责处理该请求");
            }else{
                // 如果无法处理请求,如果有下一个处理者,将请求传递给下一个处理者
                if(getNextHanler() != null){
                    getNextHanler().handlerRequest(request);
                }else{
                    System.out.println("没有人处理该请求!");
                }
            }
        }
    }
    

    3.测试

        public static void main(String[] args) {
            // 组装责任链
            Handler handlerA = new ConcreteHandlerA();
            Handler handlerB = new ConcreteHandlerB();
            handlerA.setNextHandler(handlerB);
    
            // 提交请求
            handlerA.handlerRequest("B");
        }
    

    4.结果

    具体处理者 B 负责处理该请求
    

    策略模式应用实例(登陆校验)

    不用设计模式可能我们的代码可能是这样写的

    /**
     * 会员类
     */
    public class Member {
        // 用户名
        private String loginName;
        // 密码
        private String loginPass;
        // 角色
        private String roleName;
        public Member(String loginName, String loginPass, String roleNameName){
            this.loginName = loginName;
            this.loginPass = loginPass;
            this.roleName = roleNameName;
        }
       // get set 省略....
    
    /**
     * 业务逻辑类
     */
    public class MemberService {
    
        // 用户操作一系列校验
        public void login(String loginName,String loginPass){
            if("".equals(loginName) || "".equals(loginPass)){
                System.out.println("用户名或者密码不能为空");
                return ;
            }
            System.out.println("用户名和密码不为空,可以往下执行");
    
            // 检查用户是否存在
            Member member = checkExists(loginName, loginPass);
            if(null == member){
                System.out.println("用户不存在");
                return;
            }
    
            if(!"管理员".equals(member.getRoleName())){
                System.out.println("您不是管理员,没有操作权限");
            }
            System.out.println("允许操作");
        }
    
        // 检查用户是否存在
        private Member checkExists(String loginName,String loginPass,String roleName){
            if(!"admin".equals(loginName) || !"admin".equals(loginPass)){
                return null;
            }
            Member member = new Member(loginName,loginPass,roleName);
            return member;
        }
    }
    

    登陆校验

        public static void main(String[] args) {
            MemberService ms = new MemberService();
            ms.login("admin","admin","xxx");
        }
    

    结果

    用户名和密码不为空,可以往下执行
    您是管理员
    允许操作
    

    虽然完成了功能,但是耦合性很强,代码臃肿,难扩展,不符合开闭原则

    使用责任链模式重构

    创建抽象处理类,定义具体类要实现的接口,并持有下一个处理类的引用

    /**
     * 抽象处理:定义具体类要实现的接口,并持有下一个处理类引用
     */
    public abstract class Handler {
        // 下一个处理引用
        private Handler next;
        public void setNext(Handler next){
            this.next = next;
        }
        public Handler getNext(){
            return next;
        }
        // 处理接口
        public abstract void doHandler(Member member);
    }
    

    分别创建具体处理类 ValidateHandler,LoginHandler,AuthHandler 实现抽象处理类的接口,分别做非空校验,用户校验,权限校验

    /**
     * 具体处理者:非空验证逻辑
     */
    public class ValidateHandler extends Handler{
        @Override
        public void doHandler(Member member) {
            if("".equals(member.getLoginName()) || "".equals(member.getLoginPass())){
                System.out.println("用户名或者密码不能为空");
                return ;
            }
            System.out.println("用户名和密码不为空,可以往下执行");
    
            // 调用下一个处理类
            this.getNext().doHandler(member);
        }
    }
    
    /**
     * 具体处理类:用户名密码校验逻辑
     */
    public class LoginHandler extends Handler{
        @Override
        public void doHandler(Member member) {
            // 检查用户是否存在
            Member m = checkExists(member.getLoginName(), member.getLoginPass(), member.getRoleName());
            if(null == m){
                System.out.println("用户不存在");
                return;
            }
            // 调用下一个处理类
            this.getNext().doHandler(m);
        }
        // 检查用户是否存在
        private Member checkExists(String loginName,String loginPass,String roleName){
            if(!"admin".equals(loginName) || !"admin".equals(loginPass)){
                return null;
            }
            Member member = new Member(loginName,loginPass,roleName);
            return member;
        }
    }
    
    /**
     * 具体处理类:权限校验
     */
    public class AuthHandler extends Handler{
    
        @Override
        public void doHandler(Member member) {
            if(!"管理员".equals(member.getRoleName())){
                System.out.println("您不是管理员,没有操作权限");
                return ;
            }
            System.out.println("您是管理员");
            System.out.println("允许操作");
        }
        // AuthHandler 没有下一个处理类了
    }
    

    业务逻辑类 MemberService

    /**
     * 业务逻辑类
     */
    public class MemberService {
    
        public void login(String loginName,String loignPass,String roleName){
            // 分控校验逻辑
            Handler validateHandler = new ValidateHandler();
            // 用户名密码校验逻辑
            Handler loginHandler = new LoginHandler();
            // 权限校验逻辑
            Handler authHandler = new AuthHandler();
    
            // 非空校验完毕是 用户名密码校验
            validateHandler.setNext(loginHandler);
            // 用户名密码校验完毕是 权限校验
            loginHandler.setNext(authHandler);
    
            // 权限校验完毕,没有下一个处理类了  从非空校验头链开始调用
            validateHandler.doHandler(new Member(loginName,loignPass,roleName));
        }
    }
    

    调用测试

        public static void main(String[] args) {
            MemberService ms = new MemberService();
            ms.login("admin","admin","管理员");
        }
    

    结果

    用户名和密码不为空,可以往下执行
    您是管理员
    允许操作
    

    使用责任链模式重构够后代码逻辑非常清晰,扩展方便,只需要增加新的算法类即可,符合开闭原则。但是此时的代码如何责任链类非常多的话,需要一直 next,next,next ...... 设置下一个责任处理类比较繁琐而且责任的关系维护复杂,怎么办呢?使用建造者模式优化一下

    修改抽象处理类(Handler )代码

    /**
     * 抽象处理:定义具体类要实现的接口,并持有下一个处理类引用
     */
    public abstract class Handler <T>{
        // 下一个处理引用
        private Handler next;
        public void setNext(Handler next){
            this.next = next;
        }
        public Handler getNext(){
            return next;
        }
        // 处理接口
        public abstract void doHandler(Member member);
    
        // 双向链表
        public static class Builder<T>{
            // 头部处理类
            private Handler<T> head;
            // 尾部处理类
            private Handler<T> tail;
            public Builder<T> addHandler(Handler handler){
                // 首次进入头部 尾部 都等于 handler\
                if(this.head == null){
                    this.head = this.tail = handler;
                    return this;
                }
                // 下一次不等于 null 从尾部开始追加
                this.tail.setNext(handler);
                // 把尾部替换一下
                this.tail = handler;
                return this;
            }
            // build 返回头部 从头部开始执行
            public Handler<T> build(){
                return this.head;
            }
        }
    }
    

    修改业务类(MemberService )代码

    /**
     * 业务逻辑类
     */
    public class MemberService {
    
        public void login(String loginName,String loignPass,String roleName){
    
            // 依次添加需要的校验逻辑,不需要的不添加,可以灵活删减责任,避免了众多的 if else ...
            Handler.Builder handler = new Handler.Builder();
            handler.addHandler(new ValidateHandler())
                    .addHandler(new LoginHandler())
                    .addHandler(new AuthHandler());
    
            // 怎么添加就怎么执行
            // 从头部开始执行
            handler.build().doHandler(new Member(loginName,loignPass,roleName));
        }
    }
    

    其他代码不变,最终测试一下结果是一样的,但是结构非常的清晰,责任链的关系维护简单。

    测试

        public static void main(String[] args) {
            MemberService ms = new MemberService();
            ms.login("admin","admin","管理员");
        }
    

    结果

    用户名和密码不为空,可以往下执行
    您是管理员
    允许操作
    

    相关文章

      网友评论

          本文标题:责任链模式(Chain of Responsibility Pa

          本文链接:https://www.haomeiwen.com/subject/agaophtx.html