责任链模式(Chain of Responsibility Pa

2020-04-08  本文已影响0人  吉他手_c156

责任链模式的定义与特点

定义:
责任链模式(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","管理员");
    }

结果

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

猜你喜欢

热点阅读