一、意图

  • 使多个对象都有机会处理请求,从而避免请求的发送者接收者之间的耦合关系。
  • 多个对象构成一条链,请求沿着这条链传递,直到有一个对象处理它为止。

二、适用性

  • 多个对象处理一个请求,而具体处理者仅在运行时才能确定。
  • 你想在不明确接收者的情况下,向多个中的一个提交请求。
  • 可处理一个请求的对象集合应该被动态指定时。

三、结构

职责链模式.svg

  • Handler

    1. /**
    2. * 链中的处理结点的抽象
    3. *
    4. * @author Jinhua
    5. * @date 2021/3/11下午9:34
    6. */
    7. public interface Handler {
    8. /**
    9. * 抽象职责链中单个结点的操作
    10. *
    11. * @param request 数据请求
    12. * @return 执行成功或失败
    13. */
    14. boolean handle(Object request);
    15. }
    1. 定义了处理请求的接口。
    2. (可选)实现后继链。
  • ConcreteHandler

    1. /**
    2. * 处理结点的实现 -> 权限校验处理器
    3. *
    4. * @author Jinhua
    5. * @date 2021/3/11下午9:39
    6. */
    7. public class PermissionCheckHandler implements Handler {
    8. @Override
    9. public boolean handle(Object request) {
    10. return false;
    11. }
    12. }
    1. 处理它负责的具体请求。
    2. 可访问它的后继。
    3. 如果可以处理就处理它,否则将请求转发给后继。
  • Client
    调用者,向该链发送请求。
  • Chain
    可选的一种实现,维护链结构。

    1. /**
    2. * 维护职责的链结构
    3. *
    4. * @author Jinhua
    5. * @date 2021/3/11下午10:01
    6. */
    7. public class HandlerChain {
    8. private List<Handler> handlers;
    9. public HandlerChain() {
    10. handlers = new ArrayList<>();
    11. }
    12. /**
    13. * 添加处理结点
    14. *
    15. * @param handler 处理结点,要求非空
    16. */
    17. public boolean addHandler(Handler handler) {
    18. if (Objects.isNull(handler)) {
    19. return false;
    20. }
    21. return this.handlers.add(handler);
    22. }
    23. /**
    24. * 链中的处理,若有失败则立即退出
    25. *
    26. * @param data 待处理数据
    27. * @return 处理成功或失败
    28. */
    29. public boolean process(Object data) {
    30. for (Handler handler : handlers) {
    31. boolean handle = handler.handle(data);
    32. if (!handle) {
    33. return false;
    34. }
    35. }
    36. return true;
    37. }
    38. public static void main(String[] args) {
    39. // 添加链结构
    40. HandlerChain chain = new HandlerChain();
    41. chain.addHandler(new ParamCheckHandler());
    42. chain.addHandler(new PermissionCheckHandler());
    43. chain.addHandler(new OperationHandler());
    44. // 执行链操作
    45. boolean process = chain.process("hello, world!");
    46. System.out.println(process);
    47. }
    48. }

四、效果

  1. 降低耦合度
    对象无需知道是哪个对象处理其请求,仅需知道它会被处理
  2. 增强了给对象指派职责的灵活性。
    可在运行时动态操作该链,完成对职责的增加或改变。可以将其与继承机制结合使用。
  3. 不保证被接受。
    可能到链末端仍为被处理。

五、已知应用

  1. Servlet的Filter,Interceptor机制。
  2. 常与组合模式(Composite)一起使用。

六、个人思考与扩展

  1. 对于链的结构是否可延伸为其他数据结构,比如树?
  2. 基于其他博客的说明,每个Handler处理一部分数据或是一些它感兴趣的数据。

七、一些经验

1. 小结

职责链模式太面向过程

对于web应用来讲:

  • 应当只适用于Controller传输,DAO存储中这种和基础设施交互比较多的面向过程场景,比如servlet的过滤器链。
  • 对于Service中其实面向对象更合适。

实践体会

最近看了cas单点登录的cas-client的源码,按照案例适用,它要实现单点登录机制,强依赖于它定义的过滤器的顺序,再加入proxyUrl等后续扩展的时候,其实代码的可读性已经是很大程度下降了(后续再阅读后续版本,看它是如何改进的)。