人的知识就好比一个圆圈,圆圈里面是已知的,圆圈外面是未知的。你知道得越多,圆圈也就越大,你不知道的也就越多。

0%

设计模式--责任链模式

定义

责任链模式使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。

角色

  • 抽象处理者(Handler):该角色对请求进行抽象,并定义一个方法来设定和返回对下一个处理者的引用。
  • 具体处理者(Concrete Handler):该角色收到请求后,可以选择将请求处理掉,或者将请求传给下一个处理者。由于具体处理者持有对下一个处理者的引用,因此,如果需要,处理者可以访问下一个处理者。

类图

Chain UML

实现

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");
}

// Deactivate path stripping as we exit the security filter 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);
}
}
}

...
}

实际应用

小礼物走一走,来 Github 关注我