定义 责任链模式 使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。
角色
抽象处理者(Handler):该角色对请求进行抽象,并定义一个方法来设定和返回对下一个处理者的引用。
具体处理者(Concrete Handler):该角色收到请求后,可以选择将请求处理掉,或者将请求传给下一个处理者。由于具体处理者持有对下一个处理者的引用,因此,如果需要,处理者可以访问下一个处理者。
类图
实现 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 38 39 40 41 42 43 44 public abstract class Handler { private Handler nextHandler; public abstract void handleRequest () ; public Handler getNextHandler () { return nextHandler; } public void setNextHandler (Handler nextHandler) { this .nextHandler = nextHandler; } } public class ConcreteHandler1 extends Handler { @Override public void handleRequest () { if (getNextHandler() != null ) { getNextHandler().handleRequest(); } } } public class ConcreteHandler2 extends Handler { @Override public void handleRequest () { if (getNextHandler() != null ) { getNextHandler().handleRequest(); } } } public class Client { public static void main (String[] args) { Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); handler1.setNextHandler(handler2); handler1.handleRequest(); } }
优缺点 优点
降低耦合度。它将请求的发送者和接收者解耦
简化了对象,使得对象不需要知道链的结构
增强给对象指派职责的灵活性。通过改变链的成员或调动它们的次序,允许动态的新增或删除责任
缺点
不能保证请求一定被接收
系统性能将受到影响,而且在进行代码调试时不太方便,可能会造成循环调用
适用场景
有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
可动态指定一组对象处理请求
模式应用 Spring Security是基于Filter实现安全访问的,它里面包含了大量的filters,这些filters的运行机制中就用到了责任链模式。 不过它不是标准的责任链模式,因为责任链太长或者每条链判断处理的时间太长会影响性能,所以它在实现中并没有不断地去设置next filter,而是将filters定义在数组中,然后通过递增数组下标来访问下一个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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class FilterChainProxy extends GenericFilterBean { ... private static class VirtualFilterChain implements FilterChain { private final FilterChain originalChain; private final List<Filter> additionalFilters; private final FirewalledRequest firewalledRequest; private final int size; private int currentPosition = 0 ; private VirtualFilterChain (FirewalledRequest firewalledRequest, FilterChain chain, List<Filter> additionalFilters) { this .originalChain = chain; this .additionalFilters = additionalFilters; this .size = additionalFilters.size(); this .firewalledRequest = firewalledRequest; } @Override public void doFilter (ServletRequest request, ServletResponse response) throws IOException, ServletException { if (currentPosition == size) { if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " reached end of additional filter chain; proceeding with original chain" ); } this .firewalledRequest.reset(); originalChain.doFilter(request, response); } else { currentPosition++; Filter nextFilter = additionalFilters.get(currentPosition - 1 ); if (logger.isDebugEnabled()) { logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " at position " + currentPosition + " of " + size + " in additional filter chain; firing Filter: '" + nextFilter.getClass().getSimpleName() + "'" ); } nextFilter.doFilter(request, response, this ); } } } ... }
实际应用