Java design pattern 13 - chain of responsibility pattern

hiram-QI 2020-11-09 16:06:22
java design pattern chain responsibility


The definition and characteristics of responsibility chain pattern

The definition of responsibility chain pattern : Give multiple objects a chance to process requests , This avoids the coupling between the sender and the receiver of the request , Link this object into a chain , And pass the request along the chain , Until someone deals with him .

Standard responsibility chain model , Personal summary has the following characteristics :

  • Every object in the chain has an opportunity to process requests
  • Each object in the chain holds the next reference to the object to be processed
  • An object in the chain cannot process the current request , Then it will pass the same request to the next object

Use a diagram to show the following architecture after using the responsibility chain pattern :

in other words , The responsibility chain pattern satisfies the loose coupling between the request sender and the request handler , Abstract non core parts , Processing the request object in the way of chain call .

I don't understand ? So let's show you through practical examples .

 

Don't use the responsibility chain model

Why use the responsibility chain model , Then we need to know what's wrong with not using the responsibility chain model , Then how to optimize the code by using the responsibility chain pattern .

Now there's a scene : Xiao Ming is going to school , My mother made a list for Xiao Ming before he went to school ( Wash your hair 、 have breakfast 、 wash one 's face ), Xiao Ming must follow his mother's request , You can't go to school until you've done the things on the list .

First we define a preparation list PreparationList:

 1 public class PreparationList {
2
3 /**
4 * Wash your face
5 */
6 private boolean washFace;
7
8 /**
9 * Do you wash your hair
10 */
11 private boolean washHair;
12
13 /**
14 * Breakfast or not
15 */
16 private boolean haveBreakfast;
17
18 public boolean isWashFace() {
19 return washFace;
20 }
21
22 public void setWashFace(boolean washFace) {
23 this.washFace = washFace;
24 }
25
26 public boolean isWashHair() {
27 return washHair;
28 }
29
30 public void setWashHair(boolean washHair) {
31 this.washHair = washHair;
32 }
33
34 public boolean isHaveBreakfast() {
35 return haveBreakfast;
36 }
37
38 public void setHaveBreakfast(boolean haveBreakfast) {
39 this.haveBreakfast = haveBreakfast;
40 }
41
42 @Override
43 public String toString() {
44 return "ThingList [washFace=" + washFace + ", washHair=" + washHair + ", haveBreakfast=" + haveBreakfast + "]";
45 }
46
47 }

Three things are defined : Wash your hair 、 wash one 's face 、 to have breakfast .

Then define a learning class , According to my mother's request , Finish what my mother asked before going to school :

 1 public class Study {
2
3 public void study(PreparationList preparationList) {
4 if (preparationList.isWashHair()) {
5 System.out.println(" wash one 's face ");
6 }
7 if (preparationList.isWashHair()) {
8 System.out.println(" Wash your hair ");
9 }
10 if (preparationList.isHaveBreakfast()) {
11 System.out.println(" to have breakfast ");
12 }
13
14 System.out.println(" I can go to school !");
15 }
16
17 }

This example fulfills our requirements , But not elegant enough , Our main process is learning , But couple the actions to be done with the learning , There are two problems with this :

  • PreparationList When you add one thing , For example, add makeup 、 Clean a room , Must be modified study Methods to adapt
  • When the order of these things needs to change , Must be modified study Method , For example, first wash your hair and then wash your face , that 7~9 The line code must be in line with 4~6 Lines of code are interchanged

The worst way to write , Just to satisfy the function , Against the principle of opening and closing , That is, when we expand the function, we need to modify the main process , Unable to close the modification 、 Open to expansion .

 

Use the responsibility chain model

Let's take a look at how to use the responsibility chain model , Since the characteristics of the responsibility chain model are “ Each object in the chain holds a reference to the next object ”, So let's do this .

First abstract out a AbstractPrepareFilter:

 1 public abstract class AbstractPrepareFilter {
2
3 private AbstractPrepareFilter nextPrepareFilter;
4
5 public AbstractPrepareFilter(AbstractPrepareFilter nextPrepareFilter) {
6 this.nextPrepareFilter = nextPrepareFilter;
7 }
8
9 public void doFilter(PreparationList preparationList, Study study) {
10 prepare(preparationList);
11
12 if (nextPrepareFilter == null) {
13 study.study();
14 } else {
15 nextPrepareFilter.doFilter(preparationList, study);
16 }
17 }
18
19 public abstract void prepare(PreparationList preparationList);
20
21 }

Leave an abstract method prepare Give subclasses to implement , Hold the reference to the next object in the abstract class nextPrepareFilter, If there is , execute ; If it doesn't mean that all objects in the chain have been executed , perform Study Class study() Method :

 1 public class Study {
2
3 public void study() {
4 System.out.println(" Study ");
5 }
6
7 }

Then we realize AbstractPrepareList, It's simpler , The first is shampoo :

 1 public class WashFaceFilter extends AbstractPrepareFilter {
2
3 public WashFaceFilter(AbstractPrepareFilter nextPrepareFilter) {
4 super(nextPrepareFilter);
5 }
6
7 @Override
8 public void prepare(PreparationList preparationList) {
9 if (preparationList.isWashFace()) {
10 System.out.println(" wash one 's face ");
11 }
12
13 }
14
15 }

Then wash your face :

 1 public class WashHairFilter extends AbstractPrepareFilter {
2
3 public WashHairFilter(AbstractPrepareFilter nextPrepareFilter) {
4 super(nextPrepareFilter);
5 }
6
7 @Override
8 public void prepare(PreparationList preparationList) {
9 if (preparationList.isWashHair()) {
10 System.out.println(" Wash your hair ");
11 }
12
13 }
14
15 }

Finally have breakfast :

 1 public class HaveBreakfastFilter extends AbstractPrepareFilter {
2
3 public HaveBreakfastFilter(AbstractPrepareFilter nextPrepareFilter) {
4 super(nextPrepareFilter);
5 }
6
7 @Override
8 public void prepare(PreparationList preparationList) {
9 if (preparationList.isHaveBreakfast()) {
10 System.out.println(" to have breakfast ");
11 }
12
13 }
14
15 }

Finally, let's see how the caller writes :

 1 @Test
2 public void testResponsibility() {
3 PreparationList preparationList = new PreparationList();
4 preparationList.setWashFace(true);
5 preparationList.setWashHair(false);
6 preparationList.setHaveBreakfast(true);
7
8 Study study = new Study();
9
10 AbstractPrepareFilter haveBreakfastFilter = new HaveBreakfastFilter(null);
11 AbstractPrepareFilter washFaceFilter = new WashFaceFilter(haveBreakfastFilter);
12 AbstractPrepareFilter washHairFilter = new WashHairFilter(washFaceFilter);
13
14 washHairFilter.doFilter(preparationList, study);
15 }

Now use the responsibility chain mode to modify this logic , See that we have achieved the decoupling between learning and preparation , That is, the core thing we need to learn , At this time, no matter how much preparation work is added , No need to modify study Method , Just modify the caller .

But is this a good way to write ? I think this kind of writing conforms to the principle of opening and closing , But two obvious disadvantages are not client friendly :

  • increase 、 Reduce responsibility chain objects , Need to modify client code , For example, I want to add a house cleaning operation , that testResponsibility() The method needs to be changed
  • AbstractPrepareFilter washFaceFilter = new WashFaceFilter(haveBreakfastFilter) This call is not elegant enough , Clients need to think about it , In the end, when it is called, three are called Filter Which of them? Filter

So , Let's have the ultimate version of 、 Upgraded responsibility chain model .

 

Upgraded responsibility chain mode

Above we wrote a responsibility chain model , This is a primary way to write in line with the responsibility chain model , Finally, I wrote , There are obvious shortcomings in this way of writing , Then let's take a look at how to write the updated responsibility chain model , Solve the above problems .

The following way of writing is also Servlet How to implement , The first is to abstract one Filter:

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

Notice that there is one more FilterChain, That's the chain of responsibility , It is used to string up all the responsible objects , So is it StudyPrepareFilter A subclass of :

 1 public class FilterChain implements StudyPrepareFilter {
2
3 private int pos = 0;
4
5 private Study study;
6
7 private List<StudyPrepareFilter> studyPrepareFilterList;
8
9 public FilterChain(Study study) {
10 this.study = study;
11 }
12
13 public void addFilter(StudyPrepareFilter studyPrepareFilter) {
14 if (studyPrepareFilterList == null) {
15 studyPrepareFilterList = new ArrayList<StudyPrepareFilter>();
16 }
17
18 studyPrepareFilterList.add(studyPrepareFilter);
19 }
20
21 @Override
22 public void doFilter(PreparationList thingList, FilterChain filterChain) {
23 // All filters are finished
24 if (pos == studyPrepareFilterList.size()) {
25 study.study();
26 }
27
28 studyPrepareFilterList.get(pos++).doFilter(thingList, filterChain);
29 }
30
31 }

That is, there is a counter , Suppose that all StudyPrepareFilter The call is not finished , So call the next , Otherwise execution Study Of study() Method .

Then it's easier , Realization StudyPrepareFilter The class can , First of all, shampoo :

 1 public class WashHairFilter implements StudyPrepareFilter {
2
3 @Override
4 public void doFilter(PreparationList preparationList, FilterChain filterChain) {
5 if (preparationList.isWashHair()) {
6 System.out.println(" Wash your hair ");
7 }
8
9 filterChain.doFilter(preparationList, filterChain);
10 }
11
12 }

Be careful , Here each implementation class needs to explicitly call filterChain Of doFilter Method . wash one 's face :

 1 public class WashFaceFilter implements StudyPrepareFilter {
2
3 @Override
4 public void doFilter(PreparationList preparationList, FilterChain filterChain) {
5 if (preparationList.isWashFace()) {
6 System.out.println(" Wash your face ");
7 }
8
9 filterChain.doFilter(preparationList, filterChain);
10 }
11
12 }

have breakfast :

 1 public class HaveBreakfastFilter implements StudyPrepareFilter {
2
3 @Override
4 public void doFilter(PreparationList preparationList, FilterChain filterChain) {
5 if (preparationList.isHaveBreakfast()) {
6 System.out.println(" After breakfast ");
7 }
8
9 filterChain.doFilter(preparationList, filterChain);
10 }
11
12 }

Finally, let's look at the caller :

 1 @Test
2 public void testResponsibilityAdvance() {
3 PreparationList preparationList = new PreparationList();
4 preparationList.setWashFace(true);
5 preparationList.setWashHair(false);
6 preparationList.setHaveBreakfast(true);
7
8 Study study = new Study();
9
10 StudyPrepareFilter washFaceFilter = new WashFaceFilter();
11 StudyPrepareFilter washHairFilter = new WashHairFilter();
12 StudyPrepareFilter haveBreakfastFilter = new HaveBreakfastFilter();
13
14 FilterChain filterChain = new FilterChain(study);
15 filterChain.addFilter(washFaceFilter);
16 filterChain.addFilter(washHairFilter);
17 filterChain.addFilter(haveBreakfastFilter);
18
19 filterChain.doFilter(preparationList, filterChain);
20 }

Solve the problems of the first version of the responsibility chain model perfectly , Now add 、 Modifying the client calling code of the responsible object does not need to be changed .

Some people may ask , You add 、 Reduce the number of people responsible ,testResponsibilityAdvance() Method , Not yet addFilter, Or delete a line ? Let's think back to ,Servlet We increase or decrease Filter Do you need to change any code ? no need , All we need to change is web.xml nothing more . Same thing ,FilterChain There are studyPrepareFilterList, We can put FilterChain Make one Spring Bean, be-all Filter The concrete implementation classes are Spring Bean, Inject studyPrepareFilterList Just fine , The pseudo code is :

1 <bean id="filterChain" class="xxx.xxx.xxx.FilterChain">
2 <property name="studyPrepareFilterList">
3 <list>
4 <ref bean="washFaceFilter" />
5 <ref bean="washHairFilter" />
6 <ref bean="haveBreakfastFilter" />
7 </list>
8 </property>
9 </bean>

Does this solve the problem perfectly ? We added 、 Reduce Filter, Or modify Filter The order , It just needs to be modified .xml File can , Not only does the core logic conform to the opening and closing principles , The caller also complies with the opening and closing principle .

 

The use scenario of the responsibility chain mode

That's not enough , The most typical is Servlet Medium Filter, With the above analysis , You should be able to understand Servlet The working principle of the responsibility chain model in , Then why one by one Filter It needs to be configured in web.xml in .

 

The structure of the responsibility chain model

think about it , It seems that the responsibility chain model has no complicated structure , Abstract responsibility , Implement responsible interfaces , The client initiates the call , I found a picture on the Internet to show :

 

 

Advantages and use scenarios of the responsibility chain mode

Finally, the advantages of the responsibility chain model , There are the following points :

  • It realizes the loose coupling between request sender and request handler
  • Responsibility objects can be added dynamically 、 Delete the responsible object 、 Change the order of responsible objects , Very flexible
  • Each responsible person focuses on doing his own thing , Clear responsibilities

When to use the responsibility chain model ? I think so about this question : When designing the system , It's better to distinguish primary and secondary , Which part is the core process , Which part is the auxiliary process , Are there any auxiliary processes N many if...if...if... Scene , If so, and each if There is a unified abstraction , So abstract auxiliary process , Put each if Chain call as a responsible object , Elegant implementation , Easy to reuse and expandable .

版权声明
本文为[hiram-QI]所创,转载请带上原文链接,感谢

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云