设计模式-责任链模式

什么是责任链模式

​ 当请求端Client发出请求时,为了降低请求者Client与处理对象们Handlers之间的耦合;同时满足众多Handlers都能有机会参与到对请求的处理,将Handler对象组成一条链。而请求随着链不断传递,直到被处理并返回结果。

通过定义可以发现,责任链其实有三个部分组成:

  • 客户端请求类Client:发起请求,相当于开启责任链,提交任务到责任链等待处理结果。
  • 处理类的抽象接口Handler或者抽象类:包含处理请求方法的定义,通常也包含后继链指向。
  • 具体的Handler的实现类ConcreteHandler:根据自身能力的大小对Client的请求的具体实现,有可能刚好匹配那么直接处理返回结果链的调用结束,否则将请求转发到后继链继续处理直到请求处理完成。

UML图如下:

1654525710759.png

代码示例:

Client:

1
2
3
4
5
6
7
8
9
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.oldman.run,大家都是996");
new HTMLFilter().doFilter(msg);
new SensitiveFilter().doFilter(msg);
System.out.println(msg);
}
}

Handler:

1
2
3
public interface Filter {
void doFilter(Msg msg);
}

ConcreteHandler:

1
2
3
4
5
6
7
8
9
public class HTMLFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replace('<', '[');
s = s.replace('>', ']');
msg.setMsg(s);
}
}
1
2
3
4
5
6
7
8
public class SensitiveFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replaceAll("996", "955");
msg.setMsg(s);
}
}

改造:

新增FilterChain类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class FilterChain {
List<Filter> filters = new ArrayList<>();

public FilterChain add(Filter f) {
filters.add(f);
return this;
}

public void doFilter(Msg m) {
for (Filter f : filters) {
f.doFilter(m);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.oldman.run,大家都是996");
// new HTMLFilter().doFilter(msg);
// new SensitiveFilter().doFilter(msg);
FilterChain chain = new FilterChain();
chain.add(new HTMLFilter()).add(new SensitiveFilter());
chain.doFilter(msg);
System.out.println(msg);
}
}

假如我新建另一条链,那怎么样才能连在一起

1
2
3
4
5
6
7
8
public class FaceFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replace(":)", "^V^");
msg.setMsg(s);
}
}
1
2
3
4
5
6
7
8
public class URLFilter implements Filter{
@Override
public void doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replace("www.oldman.run", "https://www.oldman.run");
msg.setMsg(s);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.oldman.run,大家都是996");
// new HTMLFilter().doFilter(msg);
// new SensitiveFilter().doFilter(msg);
FilterChain chain = new FilterChain();
chain.add(new HTMLFilter()).add(new SensitiveFilter());

FilterChain chain2 = new FilterChain();
chain2.add(new FaceFilter()).add(new URLFilter());

chain.doFilter(msg);
chain2.doFilter(msg);
System.out.println(msg);
}
}

改造后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FilterChain implements Filter{
List<Filter> filters = new ArrayList<>();

public FilterChain add(Filter f) {
filters.add(f);
return this;
}

@Override
public void doFilter(Msg m) {
for (Filter f : filters) {
f.doFilter(m);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.oldman.run,大家都是996");
// new HTMLFilter().doFilter(msg);
// new SensitiveFilter().doFilter(msg);
FilterChain chain = new FilterChain();
chain.add(new HTMLFilter()).add(new SensitiveFilter());

FilterChain chain2 = new FilterChain();
chain2.add(new FaceFilter()).add(new URLFilter());

chain.add(chain2);
chain.doFilter(msg);
System.out.println(msg);
}
}

由FilterChain中的某个Filter来决定链条是否继续,改造代码:

1
2
3
public interface Filter {
boolean doFilter(Msg msg);
}

所有实现Filter接口的类都修改doFilter方法返回值为boolean,默认返回true,其中SensitiveFilter默认返回false:

1
2
3
4
5
6
7
8
9
public class SensitiveFilter implements Filter{
@Override
public boolean doFilter(Msg msg) {
String s = msg.getMsg();
s = s.replaceAll("996", "955");
msg.setMsg(s);
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class FilterChain implements Filter{
List<Filter> filters = new ArrayList<>();

public FilterChain add(Filter f) {
filters.add(f);
return this;
}

@Override
public boolean doFilter(Msg m) {
for (Filter f : filters) {
if(!f.doFilter(m)){
return false;
}
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {
public static void main(String[] args) {
Msg msg = new Msg();
msg.setMsg("大家好:),<script>,欢迎访问www.oldman.run,大家都是996");
// new HTMLFilter().doFilter(msg);
// new SensitiveFilter().doFilter(msg);
FilterChain chain = new FilterChain();
chain.add(new HTMLFilter()).add(new SensitiveFilter());

FilterChain chain2 = new FilterChain();
chain2.add(new FaceFilter()).add(new URLFilter());

chain.add(chain2);
chain.doFilter(msg);
System.out.println(msg);
}
}
/** 执行结果: Msg{msg='大家好:),[script],欢迎访问www.oldman.run,大家都是955'} */

这时运行程序会发现,HTMLFilter、SensitiveFilter、FaceFilter、URLFilter四个过滤器中,只执行了第一个HTMLFilter,到第二个SensitiveFilter过滤器时返回了false,就停止执行后面两个过滤器了。

责任链能解决什么问题

  • 对于同一个请求可以被一系列对象结合处理,但是具体由哪个对象处理是动态决定的(运行时),那么可以将对象结合组成链的形式,考虑是否可以使用责任链简化,使结构清晰。

  • 对于接收者不明确的情况,但多个对象能够处理同一个请求,为了降低Client与Handler之间的耦合,考虑使用责任链。

缺点:

  • 当职责的增加,链的长度增加,调用栈深度加深则会影响系统的效率。
  • 职责的具体实现类如果较多,增加了一定的维护成本,同时Client端开启链时复杂度提高。

后面我们再来还原一下javax.servlet包下的Filter和FilterChain是怎么实现过滤器的。