一、意图
- 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
- 多个对象构成一条链,请求沿着这条链传递,直到有一个对象处理它为止。
二、适用性
- 有多个对象处理一个请求,而具体处理者仅在运行时才能确定。
- 你想在不明确接收者的情况下,向多个中的一个提交请求。
- 可处理一个请求的对象集合应该被动态指定时。
三、结构
Handler
/*** 链中的处理结点的抽象** @author Jinhua* @date 2021/3/11下午9:34*/public interface Handler {/*** 抽象职责链中单个结点的操作** @param request 数据请求* @return 执行成功或失败*/boolean handle(Object request);}
- 定义了处理请求的接口。
- (可选)实现后继链。
ConcreteHandler
/*** 处理结点的实现 -> 权限校验处理器** @author Jinhua* @date 2021/3/11下午9:39*/public class PermissionCheckHandler implements Handler {@Overridepublic boolean handle(Object request) {return false;}}
- 处理它负责的具体请求。
- 可访问它的后继。
- 如果可以处理就处理它,否则将请求转发给后继。
- Client
调用者,向该链发送请求。 Chain
可选的一种实现,维护链结构。/*** 维护职责的链结构** @author Jinhua* @date 2021/3/11下午10:01*/public class HandlerChain {private List<Handler> handlers;public HandlerChain() {handlers = new ArrayList<>();}/*** 添加处理结点** @param handler 处理结点,要求非空*/public boolean addHandler(Handler handler) {if (Objects.isNull(handler)) {return false;}return this.handlers.add(handler);}/*** 链中的处理,若有失败则立即退出** @param data 待处理数据* @return 处理成功或失败*/public boolean process(Object data) {for (Handler handler : handlers) {boolean handle = handler.handle(data);if (!handle) {return false;}}return true;}public static void main(String[] args) {// 添加链结构HandlerChain chain = new HandlerChain();chain.addHandler(new ParamCheckHandler());chain.addHandler(new PermissionCheckHandler());chain.addHandler(new OperationHandler());// 执行链操作boolean process = chain.process("hello, world!");System.out.println(process);}}
四、效果
- 降低耦合度
对象无需知道是哪个对象处理其请求,仅需知道它会被处理。 - 增强了给对象指派职责的灵活性。
可在运行时动态操作该链,完成对职责的增加或改变。可以将其与继承机制结合使用。 - 不保证被接受。
可能到链末端仍为被处理。
五、已知应用
- Servlet的Filter,Interceptor机制。
- 常与组合模式(Composite)一起使用。
六、个人思考与扩展
- 对于链的结构是否可延伸为其他数据结构,比如树?
- 基于其他博客的说明,每个Handler处理一部分数据或是一些它感兴趣的数据。
七、一些经验
1. 小结
职责链模式太面向过程
对于web应用来讲:
- 应当只适用于Controller传输,DAO存储中这种和基础设施交互比较多的面向过程场景,比如servlet的过滤器链。
- 对于Service中其实面向对象更合适。
实践体会
最近看了cas单点登录的cas-client的源码,按照案例适用,它要实现单点登录机制,强依赖于它定义的过滤器的顺序,再加入proxyUrl等后续扩展的时候,其实代码的可读性已经是很大程度下降了(后续再阅读后续版本,看它是如何改进的)。
