北风设计模式课程---责任链模式 总结

心已赠人 2022-01-06 23:19 309阅读 0赞

北风设计模式课程—-责任链模式 总结

一、总结

一句话总结:

设置了级别的场景:责任链适合那些已经设置了级别的场景,
都有对应的抽象类:面向对象这些设计模式,处理类或者工厂类都有对应的抽象类,比如这里责任链模式的 处理类的抽象父类,作用自然是满足 开闭原则。

1、责任链模式 比正常例子可爱一点的 例子?

古代女子逛街请示:古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。

古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。也就是说,一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈夫死了还要听从于儿子。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。估计你接下来马上要问:“要是没有儿子怎么办?”那就请示小叔子、侄子等。在父系社会中,妇女只占从属地位,现在想想中国古代的妇女还是挺悲惨的,连逛街都要多番请示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。

2、如下设计解决责任链模式的方法的缺点是什么?

|||-begin

  1. class Client {
  2. public static void main(String[] args) {
  3. // 随机挑选几个女性
  4. Random rand = new Random();
  5. ArrayList<IWoman> arrayList = new ArrayList();
  6. for (int i = 0; i < 5; i++) {
  7. arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
  8. }
  9. // 定义三个请示对象
  10. IHandler father = new Father();
  11. IHandler husband = new Husband();
  12. IHandler son = new Son();
  13. for (IWoman woman : arrayList) {
  14. if (woman.getType() == 1) { // 未结婚少女, 请示父亲
  15. System.out.println("\n--------女儿向父亲请示-------");
  16. father.HandleMessage(woman);
  17. } else if (woman.getType() == 2) { // 已婚女子, 请示丈夫
  18. System.out.println("\n--------妻子向丈夫请示-------");
  19. husband.HandleMessage(woman);
  20. } else if (woman.getType() == 3) { // 母亲请示儿子
  21. System.out.println("\n--------母亲向儿子请示-------");
  22. son.HandleMessage(woman);
  23. } else {
  24. // 暂时什么也不做
  25. }
  26. }
  27. }
  28. }

|||-end

职责界定不清晰:对女儿提出的请示,应该在父亲类中做出决定,因此 Father 类应该是知道女儿的请求自己处理,而不是在 Client 类中进行组装,不应该是这样的。
代码臃肿:我们在 Client 类中写了很多 if…else 的判断条件,而且能随着能处理该类型的请示人员越多,if…else 的判断就越多,代码就越来越臃肿,可读性就越来越低。
耦合严重:这是什么意思呢,我们要根据 Woman 的 type 来决定使用 IHandler 的那个实现类来处理请求。有一个问题是:如果 IHandler 的实现类继续扩展怎么办?修改 Client 类?这与开闭原则违背。
异常情况欠考虑:女子提出一个请示,必然要获得一个答复,甭管是同意还是不同意,总之是要一个答复的,而且这个答复是唯一的,不能说是父亲作出一个决断,而丈夫也作出了一个决断,正确的顺序应该是请求一层一层的传递的,父亲处理过后再由丈夫处理。

3、责任链抽象Handle类实例?

|||-begin

  1. public abstract class Handler {
  2. public final static int FATHER_LEVEL_REQUEST = 1;
  3. public final static int HUSBAND_LEVEL_REQUEST = 2;
  4. public final static int SON_LEVEL_REQUEST = 3;
  5. // 能处理的级别
  6. private int level = 0;
  7. // 责任传递, 下一个人责任人是谁
  8. private Handler nextHandler;
  9. // 每个类都要说明一下自己能处理哪些请求
  10. public Handler(int _level) {
  11. this.level = _level;
  12. }
  13. // 你要处理这个请求
  14. public final void HandleMessage(IWoman woman) {
  15. if (woman.getType() == this.level) {
  16. this.response(woman);
  17. } else {
  18. if (this.nextHandler != null) { // 有后续环节,
  19. this.nextHandler.HandleMessage(woman); // 才把请求往后递送this.nextHandler.HandleMessage(women);
  20. } else { // 已经没有后续处理人了, 不用处理了
  21. System.out.println("---没地方请示了, 按不同意处理---\n");
  22. }
  23. }
  24. }
  25. // 如果不属于你处理的请求, 你应该让她找下一个环节的人, 如女儿出嫁了, 还向父亲请示是否可以逛街, 那父亲就应该告诉女儿, 应该找丈夫请示
  26. public void setNext(Handler _nextHandler) {
  27. this.nextHandler = _nextHandler;
  28. }
  29. // 有请示那当然要回应
  30. protected abstract void response(IWoman woman);
  31. }

|||-end

有级别 ,有处理请求,有找自己的下一级
找下一级的操作就是:设置(获取)下一级的对象:this.nextHandler = _nextHandler;

4、责任链 设计模式 优缺点?

优点:将请求者和处理者分开,两者解耦,提供系统灵活性。
缺点:请求都是从链头遍历到链尾,当链很长的时候,性能是个很大的问题。

二、责任链模式(十二)

转自或参考:责任链模式(十二)
https://blog.csdn.net/afei\_\_/article/details/80677711

一、引子

古代女子有“三从四德”之说,“三从”即指“未嫁从父、既嫁从夫、夫死从子”。也就是说,一位女性在结婚之前要听从于父亲,结婚之后要听从于丈夫,如果丈夫死了还要听从于儿子。举例来说,如果一位女性要出去逛街,在她出嫁前必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?那就得问问儿子是否允许自己出去逛街。估计你接下来马上要问:“要是没有儿子怎么办?”那就请示小叔子、侄子等。在父系社会中,妇女只占从属地位,现在想想中国古代的妇女还是挺悲惨的,连逛街都要多番请示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。

1. 针对这个例子,我们可以先定义一个女子的接口,如下:
  1. public interface IWoman {
  2. int getType();
  3. // 获得个人请示, 你要干什么? 出去逛街? 约会?还是看电影?
  4. String getRequest();
  5. }
2. 然后定义一个古代女子的类,实现这个接口
  1. public class Woman implements IWoman {
  2. // 通过一个int类型的参数来描述妇女的个人状况 1--未出嫁 2--出嫁 3--夫死
  3. private int type = 0;
  4. // 女子的请示
  5. private String request = "";
  6. // 构造函数传递过来请求
  7. public Woman(int _type, String _request) {
  8. this.type = _type;
  9. this.request = _request;
  10. }
  11. // 获得自己的状况
  12. public int getType() {
  13. return this.type;
  14. }
  15. // 获得妇女的请求
  16. public String getRequest() {
  17. return this.request;
  18. }
  19. }

二、错误示范

假如你之前并不知道责任链模式,你可能会如下设计:

1. 父亲、丈夫、儿子都是处理者,可以这么定义
  1. public interface IHandler {
  2. // 你要处理这个请求
  3. void HandleMessage(IWoman woman);
  4. }
  5. public class Father implements IHandler {
  6. // 未出嫁的女儿请示父亲
  7. public void HandleMessage(IWoman woman) {
  8. System.out.println("父亲的答复是:同意");
  9. }
  10. }
  11. public class Husband implements IHandler {
  12. // 妻子请示丈夫
  13. public void HandleMessage(IWoman woman) {
  14. System.out.println("丈夫的答复是: 同意");
  15. }
  16. }
  17. public class Son implements IHandler {
  18. // 母亲请示儿子
  19. public void HandleMessage(IWoman woman) {
  20. System.out.println("儿子的答复是: 同意");
  21. }
  22. }
2. 如上,还差一个场景类来模拟这个场景了
  1. class Client {
  2. public static void main(String[] args) {
  3. // 随机挑选几个女性
  4. Random rand = new Random();
  5. ArrayList<IWoman> arrayList = new ArrayList();
  6. for (int i = 0; i < 5; i++) {
  7. arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
  8. }
  9. // 定义三个请示对象
  10. IHandler father = new Father();
  11. IHandler husband = new Husband();
  12. IHandler son = new Son();
  13. for (IWoman woman : arrayList) {
  14. if (woman.getType() == 1) { // 未结婚少女, 请示父亲
  15. System.out.println("\n--------女儿向父亲请示-------");
  16. father.HandleMessage(woman);
  17. } else if (woman.getType() == 2) { // 已婚女子, 请示丈夫
  18. System.out.println("\n--------妻子向丈夫请示-------");
  19. husband.HandleMessage(woman);
  20. } else if (woman.getType() == 3) { // 母亲请示儿子
  21. System.out.println("\n--------母亲向儿子请示-------");
  22. son.HandleMessage(woman);
  23. } else {
  24. // 暂时什么也不做
  25. }
  26. }
  27. }
  28. }
3. 这样也可以正常运行,但是会存在以下几个问题:
  • 职责界定不清晰
    对女儿提出的请示,应该在父亲类中做出决定,因此 Father 类应该是知道女儿的请求自己处理,而不是在 Client 类中进行组装,不应该是这样的。
  • 代码臃肿
    我们在 Client 类中写了很多 if...else 的判断条件,而且能随着能处理该类型的请示人员越多,if...else 的判断就越多,代码就越来越臃肿,可读性就越来越低。
  • 耦合严重
    这是什么意思呢,我们要根据 Womantype 来决定使用 IHandler 的那个实现类来处理请求。有一个问题是:如果 IHandler 的实现类继续扩展怎么办?修改 Client 类?这与开闭原则违背。
  • 异常情况欠考虑
    女子提出一个请示,必然要获得一个答复,甭管是同意还是不同意,总之是要一个答复的,而且这个答复是唯一的,不能说是父亲作出一个决断,而丈夫也作出了一个决断,正确的顺序应该是请求一层一层的传递的,父亲处理过后再由丈夫处理。

三、正确示范

虽然你还不知道责任链模式是怎样定义的,但是哦我们可以先来看一下它可以怎样优雅地处理上面这种情况。

1. 首先重新定义一个抽象的 Handler
  1. public abstract class Handler {
  2. public final static int FATHER_LEVEL_REQUEST = 1;
  3. public final static int HUSBAND_LEVEL_REQUEST = 2;
  4. public final static int SON_LEVEL_REQUEST = 3;
  5. // 能处理的级别
  6. private int level = 0;
  7. // 责任传递, 下一个人责任人是谁
  8. private Handler nextHandler;
  9. // 每个类都要说明一下自己能处理哪些请求
  10. public Handler(int _level) {
  11. this.level = _level;
  12. }
  13. // 你要处理这个请求
  14. public final void HandleMessage(IWoman woman) {
  15. if (woman.getType() == this.level) {
  16. this.response(woman);
  17. } else {
  18. if (this.nextHandler != null) { // 有后续环节,
  19. this.nextHandler.HandleMessage(woman); // 才把请求往后递送this.nextHandler.HandleMessage(women);
  20. } else { // 已经没有后续处理人了, 不用处理了
  21. System.out.println("---没地方请示了, 按不同意处理---\n");
  22. }
  23. }
  24. }
  25. // 如果不属于你处理的请求, 你应该让她找下一个环节的人, 如女儿出嫁了, 还向父亲请示是否可以逛街, 那父亲就应该告诉女儿, 应该找丈夫请示
  26. public void setNext(Handler _nextHandler) {
  27. this.nextHandler = _nextHandler;
  28. }
  29. // 有请示那当然要回应
  30. protected abstract void response(IWoman woman);
  31. }
2. 定义具体的实现类
  1. public class Father extends Handler {
  2. // 父亲只处理女儿的请求
  3. public Father() {
  4. super(Handler.FATHER_LEVEL_REQUEST);
  5. }
  6. protected void response(IWoman woman) {
  7. System.out.println("父亲的答复是:同意\n");
  8. }
  9. }
  10. public class Husband extends Handler {
  11. // 丈夫只处理妻子的请求
  12. public Husband() {
  13. super(Handler.HUSBAND_LEVEL_REQUEST);
  14. }
  15. protected void response(IWoman woman) {
  16. System.out.println("丈夫的答复是: 同意\n");
  17. }
  18. }
  19. public class Son extends Handler {
  20. // 儿子只处理母亲的请求
  21. public Son() {
  22. super(Handler.SON_LEVEL_REQUEST);
  23. }
  24. protected void response(IWoman woman) {
  25. System.out.println("儿子的答复是: 同意\n");
  26. }
  27. }
3. 模拟一个场景
  1. class Client {
  2. public static void main(String[] args) {
  3. // 随机挑选几个女性
  4. Random rand = new Random();
  5. ArrayList<IWoman> arrayList = new ArrayList();
  6. for (int i = 0; i < 5; i++) {
  7. arrayList.add(new Woman(rand.nextInt(4), "我要出去逛街"));
  8. }
  9. // 定义三个请示对象
  10. Handler father = new Father();
  11. Handler husband = new Husband();
  12. Handler son = new Son();
  13. // 设置请示顺序
  14. father.setNext(husband);
  15. husband.setNext(son);
  16. for (IWoman woman : arrayList) {
  17. father.HandleMessage(woman);
  18. }
  19. }
  20. }
4. 分析

结果也正确,业务调用类 Client 也不用去做判断到底是需要谁去处理,而且 Handler 抽象类的子类可以继续增加下去,只需要扩展传递链而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。在这种模式下,该父亲处理就父亲处理,不该父亲处理就往下传递。 这就是责任链模式。

四、定义

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

五、类图及通用模版

20180613131713236

一种通用模版的写法如下:

1. 抽象处理者
  1. public abstract class Handler {
  2. private Handler nextHandler;
  3. // 每个处理者都必须对请求做出处理
  4. public final Response handleMessage(Request request) {
  5. Response response = null;
  6. // 判断是否是自己的处理级别
  7. if (this.getHandlerLevel().equals(request.getRequestLevel())) {
  8. response = this.echo(request);
  9. } else { // 不属于自己的处理级别
  10. // 判断是否有下一个处理者
  11. if (this.nextHandler != null) {
  12. response = this.nextHandler.handleMessage(request);
  13. } else {
  14. // 没有适当的处理者, 业务自行处理
  15. }
  16. }
  17. return response;
  18. }
  19. // 设置下一个处理者是谁
  20. public void setNext(Handler _handler) {
  21. this.nextHandler = _handler;
  22. }
  23. // 每个处理者都有一个处理级别
  24. protected abstract Level getHandlerLevel();
  25. // 每个处理者都必须实现处理任务
  26. protected abstract Response echo(Request request);
  27. }

这里抽象的处理者实现三个职责:一是定义一个请求的处理方法 handleMessage,也是唯一对外开放的方法;二是定义一个链的编排方法 setNext,设置下一个处理者; 三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别 getHandlerLevel 和具体的处理任务 echo
注意这里 handleMessage 方法前面的 final 关键字,这里其实就是模版方法的一个使用,父类定义了部分方法的执行顺序,实际实现却是子类完成。

2. 其它相关接口类
  1. public interface Request {
  2. // 获取请求的等级
  3. Level getRequestLevel();
  4. }
  5. public interface Response {
  6. // 返回的结果
  7. }
  8. public interface Level {
  9. // 等级的定义
  10. }
3. 场景类
  1. class Client {
  2. public static void main(String[] args) {
  3. // 声明所有的处理节点
  4. Handler handler1 = new ConcreteHandler1();
  5. Handler handler2 = new ConcreteHandler2();
  6. Handler handler3 = new ConcreteHandler3();
  7. // 设置链中的阶段顺序1-->2-->3
  8. handler1.setNext(handler2);
  9. handler2.setNext(handler3);
  10. Request request = new ConcreteRequest();
  11. // 提交请求, 返回结果
  12. Response response = handler1.handleMessage(request);
  13. }
  14. }

其实在实际应用中,一般还有有一个类来封装责任链,完成责任链的顺序编排,并返回链中的第一个处理者,这样上层逻辑就不再需要设置具体的责任链了,简化了上层逻辑,减少了模块间的耦合,系统也会更灵活。

六、优缺点

  • 优点
    将请求者和处理者分开,两者解耦,提供系统灵活性。
  • 缺点
    请求都是从链头遍历到链尾,当链很长的时候,性能是个很大的问题。
    一般我们可以在 Handler 中设置一个最大节点数量,在 setNext 方法中判断是否已经超过最大节点数,超过则不允许继续添加处理者,避免无意识的破坏系统性能。

转载于:https://www.cnblogs.com/Renyi-Fan/p/11073444.html

发表评论

表情:
评论列表 (有 0 条评论,309人围观)

还没有评论,来说两句吧...

相关阅读