设计模式------责任链模式详解

责任链模式

目录

责任链模式

1、什么是责任链模式

2、结构图

3、实例

4、小结


1、什么是责任链模式

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

举个简单的例子,比如我们进行登录验证时,首先需要验证用户名和密码是否为空,然后验证用户名和密码是否正确,然后还要验证是用户的类型。那么这时候就可以认为每一次验证就是一个对象结点,依次进行验证。

2、结构图

           

  • 责任链模式包含如下角色
    • Handler(抽象处理者):所有具体处理者的父类,一般定义为抽象类,定义了一个统一的处理入口,以及维持了一个抽象处理者类型对象的引用,用于形成链式处理者
    • ConcreteHandler(具体处理者):继承抽象处理者,实现统一的处理入口,将自己无法处理的请求转发给下一个处理者
  • 处理链的形成是在客户端完成的,以及处理链的顺序也是客户端决定的
  • 纯的责任链模式
    • 处理者只有两种选择,要么全部处理请求,要么全部不处理,不能只处理一部分请求
    • 请求必须被处理,不存在请求最终未被处理的情况发生
  • 不纯的责任链模式
    • 可以处理部分,然后将请求转发给下一个处理者处理
    • 请求可以不被所有处理者处理

3、实例

     下面的实例演示:用户登录的验证过程,其中结合了建造者模式中的链接式代码风格。

/**
 * @description: 用户实体类
 * @author: zps
 * @create: 2020-05-04 19:43
 **/
@Data
public class Member {

    private String loginName; //登录名
    private String loginPass; //登录密码
    private String roleName;  //用户角色

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

/**
 * @description: 抽象处理者
 * @author: zps
 * @create: 2020-05-04 17:59
 **/
public abstract class Handler {

    protected Handler chain;  //下一个处理者

    public void next(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(this.head == null){
                this.head = this.tail = handler;
                return this;
            }
            this.tail.next(handler);//为当前对象添加下一个对象
            this.tail = handler;
            return this;
        }

        public Handler builder(){
            return this.head;
        }
    }
}

/**
 * @description: 非空验证
 * @author: zps
 * @create: 2020-05-04 19:51
 **/
public class ValidateHandler extends Handler {
    @Override
    public void doHandle(Member member) {
        if(StringUtils.isEmpty(member.getLoginName())
            && StringUtils.isEmpty(member.getLoginPass())){
            System.out.println("用户名或者密码为空!");
            return;
        }
        System.out.println("用户名何密码验证为非空!正在进行下一步验证");
        chain.doHandle(member);
    }
}

/**
 * @description: 登录验证
 * @author: zps
 * @create: 2020-05-04 19:48
 **/
public class LoginHandler extends Handler {
    @Override
    public void doHandle(Member member) {
        //这里可以从数据库进行查询验证,在这里就默认用户存在
        System.out.println("登录成功!");
        //进行一个验证
        chain.doHandle(member);

    }
}

/**
 * @description: 用户权限验证
 * @author: zps
 * @create: 2020-05-04 19:55
 **/
public class AuthHandler extends Handler{
    @Override
    public void doHandle(Member member) {
        if(member.getRoleName().equals("管理员")){
            System.out.println("您是管理员,允许操作!");
        }else{
            System.out.println("您不是管理员,不允许操作!");
        }
    }
}

/**
 * @description: 登录服务
 * @author: zps
 * @create: 2020-05-04 19:57
 **/
public class LoginService {
     public void login(String 张三, String loginName, String loginPass){
         Handler.Builder builder = new Handler.Builder();
         builder.addHandler(new ValidateHandler())
                 .addHandler(new LoginHandler())
                 .addHandler(new AuthHandler());
         builder.builder().doHandle(new Member(loginName , loginPass , "管理员"));
     }
}

/**
 * @description: 测试
 * @author: zps
 * @create: 2020-05-04 20:08
 **/
public class Test {
    public static void main(String[] args) {
        LoginService loginService = new LoginService();
        loginService.login("张三" ,"zhangsan" , "管理员");
    }
}

测试结果:

4、小结

职责链模式的主要优点

  • 对象仅需知道该请求会被处理即可,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度
  • 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接
  • 在给对象分派职责时,职责链可以给我们更多的灵活性,可以在运行时对该链进行动态的增删改,改变处理一个请求的职责
  • 新增一个新的具体请求处理者时无须修改原有代码,只需要在客户端重新建链即可,符合 "开闭原则"

职责链模式的主要缺点

  • 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,且不方便调试
  • 可能因为职责链创建不当,造成循环调用,导致系统陷入死循环

适用场景

  • 多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求

源码中的使用常见场景

  • Tomcat 过滤器中的责任链模式

    Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:在客户端的请求访问后端资源之前,拦截这些请求;在服务器的响应发送回客户端之前,处理这些响应。Servlet 定义了过滤器接口 Filter 和过滤器链接口 FilterChain 的源码如下

public interface Filter {
    public void init(FilterConfig filterConfig) throws ServletException;
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
    public void destroy();
}

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
  •  Netty 中的 Pipeline 和 ChannelHandler 通过责任链设计模式来组织代码逻辑
  • Spring AOP 通过责任链模式来管理 Advisor
  • Mybatis 中的 Plugin 机制使用了责任链模式,配置各种官方或者自定义的 Plugin,与 Filter 类似,可以在执行 Sql 语句的时候做一些操作
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值