Java责任链模式

本文最后更新于:2022年7月13日 下午

概览:责任链模式

责任链模式

将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象处理。

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

参考链接:Java设计模式13:责任链模式 - 五月的仓颉 - 博客园 (cnblogs.com)

Java责任链模式(Chain of responsibility) - 腾讯云开发者社区-腾讯云 (tencent.com)

案例:洗脸、吃饭、学习

学习之前要洗脸和吃饭等动作,完成之后才进行学习,普通编程如何处理呢?

  • 直接先执行洗脸和吃饭任务,然后再学习
  • 问题:新增任务或者修改顺序比较复杂违反开闭原则

责任链优化:

  • 责任链上的每个对象都要去引用下一个对象

任务列表:

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
public class PreparationList {

/**
* 是否洗脸
*/
private boolean washFace;

/**
* 是否洗头
*/
private boolean washHair;

/**
* 是否吃早餐
*/
private boolean haveBreakfast;

public boolean isWashFace() {
return washFace;
}

public void setWashFace(boolean washFace) {
this.washFace = washFace;
}

public boolean isWashHair() {
return washHair;
}

public void setWashHair(boolean washHair) {
this.washHair = washHair;
}

public boolean isHaveBreakfast() {
return haveBreakfast;
}

public void setHaveBreakfast(boolean haveBreakfast) {
this.haveBreakfast = haveBreakfast;
}

@Override
public String toString() {
return "ThingList [washFace=" + washFace + ", washHair=" + washHair + ", haveBreakfast=" + haveBreakfast + "]";
}

}

抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractPrepareFilter {
private AbstractPrepareFilter nextPrepareFilter;

public AbstractPrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
this.nextPrepareFilter = nextPrepareFilter;
}

public void doFilter(PreparationList preparationList, Study study){
prepare(preparationList);

if(nextPrepareFilter == null){
study.study();
}else{
nextPrepareFilter.doFilter(preparationList,study);
}
}

public abstract void prepare(PreparationList preparationList);
}

洗脸行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class WashFacePrepareFilter extends AbstractPrepareFilter{

public WashFacePrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
super(nextPrepareFilter);
}

@Override
public void prepare(PreparationList preparationList) {
if (preparationList.isWashFace()) {
System.out.println("洗脸");
}
}
}

吃饭行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class EatFoodPrepareFilter extends AbstractPrepareFilter{

public EatFoodPrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
super(nextPrepareFilter);
}

@Override
public void prepare(PreparationList preparationList) {
if (preparationList.isHaveBreakfast()) {
System.out.println("吃早餐");
}
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws Exception {
PreparationList preparationList = new PreparationList();
preparationList.setWashFace(true);
preparationList.setHaveBreakfast(true);

Study study = new Study();

AbstractPrepareFilter haveBreakfastFilter = new EatFoodPrepareFilter(null);
// 将行为串接起来
AbstractPrepareFilter washFaceFilter = new WashFacePrepareFilter(haveBreakfastFilter);
washFaceFilter.doFilter(preparationList, study);
}

问题:

对于客户端来说,行为串起来的模式都需要考虑。

案例优化

新建接口

1
2
3
public interface StudyPrepareFilter {
public void doFilter(PreparationList preparationList, FilterChain filterChain);
}

新建责任链:FilterChain

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
public class FilterChain implements StudyPrepareFilter {

private int pos = 0;

private Study study;

private List<StudyPrepareFilter> studyPrepareFilterList;

public FilterChain(Study study) {
this.study = study;
}

public void addFilter(StudyPrepareFilter studyPrepareFilter) {
if (studyPrepareFilterList == null) {
studyPrepareFilterList = new ArrayList<StudyPrepareFilter>();
}

studyPrepareFilterList.add(studyPrepareFilter);
}

@Override
public void doFilter(PreparationList thingList, FilterChain filterChain) {
// 所有过滤器执行完毕
if (pos == studyPrepareFilterList.size()) {
study.study();
}else{
studyPrepareFilterList.get(pos++).doFilter(thingList, filterChain);
}
}

}

实现洗发

1
2
3
4
5
6
7
8
9
10
11
public class WashHairFilter implements StudyPrepareFilter {

@Override
public void doFilter(PreparationList preparationList, FilterChain filterChain) {
if (preparationList.isWashHair()) {
System.out.println("洗完头发");
}
filterChain.doFilter(preparationList, filterChain);
}

}

实现吃早餐

1
2
3
4
5
6
7
8
9
10
11
public class HaveBreakfastFilter implements StudyPrepareFilter {

@Override
public void doFilter(PreparationList preparationList, FilterChain filterChain) {
if (preparationList.isHaveBreakfast()) {
System.out.println("吃完早饭");
}
filterChain.doFilter(preparationList, filterChain);
}

}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) throws Exception {
PreparationList preparationList = new PreparationList();
preparationList.setWashHair(true);
preparationList.setHaveBreakfast(true);

Study study = new Study();
StudyPrepareFilter washHairFilter = new WashHairFilter();
StudyPrepareFilter haveBreakfastFilter = new HaveBreakfastFilter();

FilterChain filterChain = new FilterChain(study);
filterChain.addFilter(washHairFilter);
filterChain.addFilter(haveBreakfastFilter);

filterChain.doFilter(preparationList, filterChain);
}

FilterChain可以作为spring bean来注入。

核心概览:

  1. FilterChain表示责任链,内部有一个list对象来存储各个filter,list的先后顺序就是执行的先后顺序。

结合Spring来使用

自定义排序注解

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.core.Ordered;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
public @interface FilterOrder {

/**
* 越小优先级越高
*/
int value() default Ordered.LOWEST_PRECEDENCE;
}

任务列表增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Service
public class FilterChain implements InitializingBean {

@Resource
private List<Filter> filterList;

public void doFilter(BanCallBackContext context) {
for (Filter filter : filterList) {
if (!filter.do(context)) {
return;
}
}
}


// 填充到filterList中,按照标写的顺序执行
@Override
public void afterPropertiesSet() {
filterList = filterList.stream()
.sorted(Comparator.comparingInt(filter -> filter.getClass().getAnnotation(FilterOrder.class).value())
.thenComparing(filter -> filter.getClass().getSimpleName()))
.collect(Collectors.toList());
}
}