责任链模式
目录
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 语句的时候做一些操作