责任链模式基本介绍

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

责任链模式类图

在这里插入图片描述
从类图可以看到,责任链模式主要包含两种角色

  1. 抽象处理者(Handler):定义一个请求处理的方法,并维护一个下一个处理节点Handler对象的引用;
  2. 具体处理者(ConcreteHandler):对请求进行处理,如果不感兴趣,则进行转发

责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解的是其模式(道)而不是其具体实现(术),责任链模式的独到之处是其将节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动了起来。

责任链模式案例

我们利用责任链模式完成一个登录案例,在这个案例中我们将会对数据进行层层拦截校验

代码如下:

public class Member {
    private String loginName;
    private String loginPass;
    private String roleName;

    public Member(String loginName, String loginPass) {
        this.loginName = loginName;
        this.loginPass = loginPass;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
}


/**
 * 抽象类,定义请求处理方法,并且维护下一个节点
 */
public abstract class Handler {

    protected Handler chain;

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

    public abstract void doHandler(Member member);
}




/**
 * 用户名密码校验
 */
public class ValidateHandler extends Handler{

    @Override
    public void doHandler(Member member) {
        if(member.getLoginName() == null || member.getLoginPass() == null){
            System.out.println("用户名密码为空");
            return;
        }

        System.out.println("用户名密码校验成功,可以往下执行");
        chain.doHandler(member);
    }
}


/**
 * 登录
 */
public class LoginHandler extends Handler{
    @Override
    public void doHandler(Member member) {
        System.out.println("登录成功");
        member.setRoleName("管理员");
        chain.doHandler(member);
    }
}

/**
 * 角色权限校验
 */
public class AuthHandler extends Handler{

    @Override
    public void doHandler(Member member) {
        if(!"管理员".equals(member.getRoleName())){
            System.out.println("您不是管理员不允许操作");
            return;
        }

        System.out.println("您是管理员,允许操作");
    }
}



/**
 * 将前面定义好的Handler,串联起来,形成一条链
 */
public class MemberService {
   public void login(String loginName,String loginPass){
       Handler validateHandler = new ValidateHandler();
       Handler loginHandler = new LoginHandler();
       Handler authHandler = new AuthHandler();
       validateHandler.next(loginHandler);
       loginHandler.next(authHandler);
       Member member = new Member(loginName,loginPass);
       validateHandler.doHandler(member);
    }
}

/**
 * 客户端代码测试
 */
public class Test {
    public static void main(String[] args) {
        MemberService memberService = new MemberService();
        memberService.login("tom","666");
    }
}


结果:

用户名密码校验成功,可以往下执行
登录成功
您是管理员,允许操作

其实我们平时使用的很多权限校验框架都是运用这样一个原理的

责任链模式和建造者模式结合使用

从上面的代码中我们可以看到负责组装链式结构的角色是MemberService,但是如果链式结构比较长的话,MemberService就会显得很臃肿,且后续更改处理者时,MemberService都要变动,不符合开闭原则。所以对这种复杂结构的创建,我们可以使用建造者模式,我们完全可以将节点对象进行自动的链式组装。客户只需要指定处理节点对象,以及对象的顺序即可。
我们来改造一下Handler的代码

/**
 * 抽象类,定义请求处理方法,并且维护下一个节点
 */
public abstract class Handler<T> {

    protected Handler chain;

    private void next(Handler handler) {
        this.chain = handler;
    }

    public abstract void doHandler(Member member);

    public static class Builder<T>{
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler<T> handler){
            if(this.head == null){
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);
            this.tail = handler;

            return this;
        }

        public Handler<T> build() {
            return this.head;
        }
    }
}


MemberServcice 也需要修改一下

/**
 * 将前面定义好的Handler,串联起来,形成一条链
 */
public class MemberService {
   public void login(String loginName,String loginPass){
       Handler.Builder builder = new Handler.Builder();
       builder.addHandler(new ValidateHandler())
               .addHandler(new LoginHandler())
               .addHandler(new AuthHandler());
       Member member = new Member(loginName,loginPass);
       builder.build().doHandler(member);
    }
}


责任链模式在源码中的体现

SpringMVC-HandlerExecutionChain类使用了责任链模式,他的主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只是将请求分配给链上注册处理器执行,这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程。HandlerExecutionChain 维护了 HandlerInterceptor 的集合, 可以向其中注册相应的拦截器

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐