定义 责任链模式又叫职责链模式。为请求创建一个接收此次请求的对象的链,这个链条由多个对象组成。
类型 行为型
适用场景
优点 1 2 3 1.请求的发送者和接收者(请求的处理者)解耦 2.责任链可以动态组合 3.责任链方便扩展和收缩(增加或减少处理对象)
缺点 1 2 1. 责任链太长或者处理时间过长会影响性能 2. 责任链有可能过多
相关的设计模式 责任链模式和状态模式
1 责任链模式中各个对象不会指定下一个处理对象是谁,只有在客户端设定链条中的顺序以及元素直到被某个元素处理或整条链结束。状态模式是让每个状态对象知道自己下一个处理的对象是谁,在编译时就设定好了。
简单需求 在注册网站的时候,我们需要提供用户名、邮箱以及密码,网站会有一个校验流程,分别对用户名、邮箱以及密码进行校验,如果任何一个步骤没有通过就不能注册,只有全部校验通过才能完成注册。
责任链模式演练
责任链的构建是由客户端决定的,责任链的入口也是客户端决定的
待处理的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.design.pattern.chain;import lombok.AllArgsConstructor;import lombok.Data;@Data @AllArgsConstructor public class User { private String name; private String email; private String password; }
处理器父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.design.pattern.chain;public abstract class Handler { protected Handler handler; public void setNextHandler (Handler handler) { this .handler = handler; } protected abstract void handle (User user) ; }
名称处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.design.pattern.chain;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.util.ObjectUtils;@Slf 4jpublic class NameHandler extends Handler { @Override protected void handle (User user) { if (StringUtils.isNotBlank(user.getName())){ log.info("用户名符合要求" ); if (!ObjectUtils.isEmpty(super .handler)){ super .handler.handle(user); return ; }else { log.info("完成注册" ); } return ; } log.info("用户名校验不通过,结束校验" ); } }
邮箱处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.design.pattern.chain;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.util.ObjectUtils;@Slf 4jpublic class EmailHandler extends Handler { @Override protected void handle (User user) { if (StringUtils.isNotBlank(user.getEmail())){ log.info("邮箱符合要求" ); if (!ObjectUtils.isEmpty(super .handler)){ super .handler.handle(user); return ; }else { log.info("完成注册" ); } return ; } log.info("邮箱验证不通过,验证结束" ); } }
密码处理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.design.pattern.chain;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.util.ObjectUtils;@Slf 4jpublic class PasswordHandler extends Handler { @Override protected void handle (User user) { if (StringUtils.isNotBlank(user.getPassword()) && user.getPassword().length() >5 ){ log.info("密码符合要求" ); if (!ObjectUtils.isEmpty(super .handler)){ super .handler.handle(user); return ; }else { log.info("完成注册" ); } return ; } log.info("密码验证不通过,验证结束" ); } }
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.design.pattern.chain;import org.junit.Test;public class Client { @Test public void test () { User user = new User("shunhua" ,"gentryhuang.xw@gmail.com" ,"123456" ); NameHandler nameHandler = new NameHandler(); EmailHandler emailHandler = new EmailHandler(); PasswordHandler passwordHandler = new PasswordHandler(); nameHandler.setNextHandler(emailHandler); emailHandler.setNextHandler(passwordHandler); nameHandler.handle(user); } }
责任链在源码中的使用 过滤器-Filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public abstract class OncePerRequestFilter extends GenericFilterBean { public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED" ; public OncePerRequestFilter () { } public final void doFilter (ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { HttpServletRequest httpRequest = (HttpServletRequest)request; HttpServletResponse httpResponse = (HttpServletResponse)response; String alreadyFilteredAttributeName = this .getAlreadyFilteredAttributeName(); boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null ; if (!hasAlreadyFilteredAttribute && !this .skipDispatch(httpRequest) && !this .shouldNotFilter(httpRequest)) { request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); try { this .doFilterInternal(httpRequest, httpResponse, filterChain); } finally { request.removeAttribute(alreadyFilteredAttributeName); } } else { filterChain.doFilter(request, response); } } else { throw new ServletException("OncePerRequestFilter just supports HTTP requests" ); } } }