小时候写日记都是这么写的:上午七点起床,八点之前洗脸刷牙吃早饭,十二点之前好好上课,中午一点,吃午饭,下午两点到六点,上课,下课,找请假,明天妈妈要带我去姥姥家,九点之前,看动画片,九点钟,收拾去姥姥家的东西,十点以后,睡觉。

我们把请假这块在充实一下:找班长请假,班长只能请半天,否则班长向老师申请,如果请假时间超过一周,老师要跟副年级主任请示,如果请假超出一个月,主任要跟年级正主任请示,然后被批准,或不被批准。

如果用编程语言描述这两件事情,应该是这个样子的。

  1. public class DayWork
  2. {
  3. private int hour;
  4. public void writeProgram()
  5. {
  6. if (hour < 7)
  7. {
  8. System.out.println("当前时间:" + hour + "点 睡觉");
  9. }
  10. else if (hour = 7)
  11. {
  12. System.out.println("当前时间:" + hour + "洗脸刷牙吃早饭");
  13. }
  14. else if (hour < 12)
  15. {
  16. System.out.println("当前时间:" + hour + "点 好好上课");
  17. }
  18. else if(hour=1)
  19. {
  20. System.out.println("当前时间:" + hour + "点 吃午饭");
  21. }
  22. else if(hour<18)
  23. {
  24. System.out.println("当前时间:" + hour + "点 好好学习");
  25. }
  26. }
  27. public int getHour()
  28. {
  29. return hour;
  30. }
  31. public void setHour(int hour)
  32. {
  33. this.hour = hour;
  34. }
  35. }
  36. //客户端代码
  37. public class Main
  38. {
  39. public static void main(String[] args)
  40. {
  41. DayWork work = new Work();
  42. work.setHour(9);
  43. work.writeProgram();
  44. work.setHour(10);
  45. work.writeProgram();
  46. work.setHour(12);
  47. work.writeProgram();
  48. work.setHour(13);
  49. work.writeProgram();
  50. work.setHour(14);
  51. work.writeProgram();
  52. }
  53. }

而请假的代码和这个差不多,if 请半天,班长请,else if 一周以内,老师请 else if 一个月以内 副主任请,else 超过一个月 主任请。

可是,拿日记例子来看,过多的if分支并不是一件好事,它首先不满足开闭原则,一旦需要修改整个IF语句都需要修改,责任没有费解,也不符合单一职责原则,我们希望分解整个行为,把状态的判断逻辑转移到表示不同状态的一系列类当中,把复杂的判断逻辑简化,这就是我们所说的状态模式。

状态模式结构图:

状态模式代码实现:

  1. //State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
  2. public interface State
  3. {
  4. public void handle(Context context);
  5. }
  6. //ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。
  7. public class ConcreteStateA implements State
  8. {
  9. public void handle(Context context)
  10. {
  11. context.setState(new ConcreteStateB());
  12. }
  13. }
  14. public class ConcreteStateB implements State
  15. {
  16. public void handle(Context context)
  17. {
  18. context.setState(new ConcreteStateA());
  19. }
  20. }
  21. //Context类,维护一个ConcreteState子类的实例,这个实例定义当前的状态
  22. public class Context
  23. {
  24. private State   state;
  25. public Context(State state)
  26. {
  27. this.state = state;
  28. }
  29. public void request()
  30. {
  31. state.handle(this);
  32. }
  33. public State getState()
  34. {
  35. return state;
  36. }
  37. public void setState(State state)
  38. {
  39. this.state = state;
  40. System.out.println("当前状态:" + state.getClass().getName());
  41. }
  42. }
  43. //客户端代码
  44. public class Main
  45. {
  46. public static void main(String[] args)
  47. {
  48. Context context = new Context(new ConcreteStateA());
  49. context.request();
  50. context.request();
  51. context.request();
  52. context.request();
  53. }
  54. }

状态模式将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。

而且,状态模式把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。

请假问题也是一个很复杂的条件表达式,安理说用状态模式是可以使用的。

但是,这里有一个问题,就是,如果班长请假了,用状态模式的道理讲,就是其他学生都请不了假了,也就是如果状态模式中任何一环缺失的话,这个事件都无法进行下去,怎么办?

这就需要我们的职责链模式。

结构图:

代码实现:

    1. <pre name="code" class="html">// Chain of Responsibility pattern -- Structural example
    2. using System;
    3. // "Handler"
    4. abstract class Handler
    5. {
    6. // Fields
    7. protected Handler successor;
    8. // Methods
    9. public void SetSuccessor( Handler successor )
    10. {
    11. this.successor = successor;
    12. }
    13. abstract public void HandleRequest( int request );
    14. }
    15. // "ConcreteHandler1"
    16. class ConcreteHandler1 : Handler
    17. {
    18. // Methods
    19. override public void HandleRequest( int request )
    20. {
    21. if( request >= 0 && request < 10 )
    22. Console.WriteLine("{0} handled request {1}",
    23. this, request );
    24. else
    25. if( successor != null )
    26. successor.HandleRequest( request );
    27. }
    28. }
    29. // "ConcreteHandler2"
    30. class ConcreteHandler2 : Handler
    31. {
    32. // Methods
    33. override public void HandleRequest( int request )
    34. {
    35. if( request >= 10 && request < 20 )
    36. Console.WriteLine("{0} handled request {1}",
    37. this, request );
    38. else
    39. if( successor != null )
    40. successor.HandleRequest( request );
    41. }
    42. }
    43. // "ConcreteHandler3"
    44. class ConcreteHandler3 : Handler
    45. {
    46. // Methods
    47. override public void HandleRequest( int request )
    48. {
    49. if( request >= 20 && request < 30 )
    50. Console.WriteLine("{0} handled request {1}",
    51. this, request );
    52. else
    53. if( successor != null )
    54. successor.HandleRequest( request );
    55. }
    56. }
    57. /**//// <summary>
    58. /// Client test
    59. /// </summary>
    60. public class Client
    61. {
    62. public static void Main( string[] args )
    63. {
    64. // Setup Chain of Responsibility
    65. Handler h1 = new ConcreteHandler1();
    66. Handler h2 = new ConcreteHandler2();
    67. Handler h3 = new ConcreteHandler3();
    68. h1.SetSuccessor(h2);
    69. h2.SetSuccessor(h3);
    70. // Generate and process request
    71. int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };
    72. foreach( int request in requests )
    73. h1.HandleRequest( request );
    74. }
    75. }

职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象练成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

从代码中我们可以看出,职责链模式的链式在客户端连接的,也就是说,如果我们请假,请假制度一旦改变,比如说我们不需要班长,或者是先请求老师后直接请求主任或者中间多了一个环节,都是很容易实现的,所以,职责链模式要比状态模式灵活很多。

但是,这时候是不是有人要问,都可以解决If分支过多,是不是职责链模式比状态模式好呢,还是那句话,存在即合理,职责链模式虽然灵活,但是他过于灵活,我们在使用时需要确定下一个对象是谁,在多次设置的时候很容易出问题,所以,这时候用状态模式就比较好,就像我们记录一天的行为,事情已经发生,如果用职责链模式就显得画蛇添足了。

从定义来看,状态模式是一个对象的内在状态发生改变(一个对象,相对比较稳定,处理完一个对象下一个对象的处理一般都已确定),而职责链模式是多个对象之间的改变(多个对象之间的话,就会出现某个对象不存在的现在,就像请假例子中的班长或者老师可能缺勤),这也说明他们两个模式处理的情况不同。

其实,这两个设计模式最大的区别就是状态模式是让各个状态对象自己知道其下一个处理的对象是谁,即在编译时便设定好了的;

而职责链模式中的各个对象并不指定其下一个处理的对象到底是谁,只有在客户端才设定。用我们通俗的编程语言来说,就是

状态模式:
  相当于If else if else;
  设计路线:各个State类的内部实现(相当于If,else If内的条件)
  执行时通过State调用Context方法来执行。
职责链模式:
  相当于Swich case
  设计路线:客户设定,每个子类(case)的参数是下一个子类(case)。
  使用时,向链的第一个子类的执行方法传递参数就可以。

就像对设计模式的总结,有的人采用的是状态模式,从头到尾,提前一定定义好下一个处理的对象是谁,而我采用的是职责链模式,随时都有可能调整链的顺序

状态模式、职责链模式——省去if-else的繁琐结构的更多相关文章

  1. 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

    责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...

  2. 5.js模式-职责链模式

    1. 职责链模式 将对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止. var chain = function(fn){ this.fn = fn; this.successor = ...

  3. JS模式--职责链模式

    职责链模式的定义:使用多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链, 并沿着这条链条传递下去,直到有一个对象处理它为止. var order500 = f ...

  4. [Python设计模式] 第24章 加薪审批——职责链模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下情景 员工向经理发起加薪申请,经理无权决定,需要向总监汇报, ...

  5. C#设计模式——职责链模式(Chain Of Responsibility Pattern)

    一.概述 在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使 ...

  6. 大话设计模式Python实现-职责链模式

    职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接收者的耦合关系.将对象连成链并沿着这条链传递请求直到被处理 下面是一个设计模式的demo: ...

  7. C#设计模式学习笔记:(20)职责链模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8109100.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第八个模式--职 ...

  8. 职责链模式vs状态模式区别

    状态模式在具体状态里设置了下一状态. 而职责链模式是在客户端代码里设置了下一状态的处理对象. 如果状态模式里的任何一环缺失,将导致事情无法进行下去.职责链模式的链式在客户端连接的,也就是说,如果我们请 ...

  9. C#设计模式系列:职责链模式(Chain of Responsibility)

    1.职责链模式简介 1.1>.定义 职责链模式是一种行为模式,为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求.将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对 ...

随机推荐

  1. 使用交互式方式在SQL server2017上创建数据库

    软件基础:在电脑上提前安装好SQL server2017,并且安装好其中的SSMS(SQL server Management Studio) 创建方式:交互式 操作内容:创建学生课程数据库系统 步骤 ...

  2. ansible批量加用户

    ansible批量加用户 1.生成密码 pip install passlib python -c "from passlib.hash import sha512_crypt; print ...

  3. web开发 c/s结构 和 b/s结构

    web开发 c/s结构 和 b/s结构 c/s结构 --client/server 客户端/服务器机构 如qq b/s结构 -- browser/server 浏览器/服务器结构 如网站 mvc设计 ...

  4. jdk 动态代理源码分析

    闲来无事,撸撸源码 使用方法 直接看代码吧.. package com.test.demo.proxy; import java.lang.reflect.InvocationHandler; imp ...

  5. [测试题]神在夏至祭降下了神谕(oracle)

    Description 我们村子在过去的 400 年中, 断绝与下界的接触, 过着自给自足的生活.夏至祭是一场迎接祖灵于夏季归来, 同时祈求丰收的庆典.村里的男人会在广场上演出夏之军和冬之军的战争. ...

  6. [HNOI2012]集合选数

    题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中. 同学们不喜 ...

  7. Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined)

    运气好,分到的房里我最先开始Hack C题,Hack了12个,听说F题沙雕莫队但我不会,最后剩不到15分钟想出E题做法打了一波结果挂了,最后虽然上分了但总有点不甘心. 最后A掉ABCD Hack+12 ...

  8. [USACO 5.1.3]乐曲主题

    Description 我们用N(1 <= N <=5000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,每个数表示钢琴上的一个键.很不幸这种表示旋律的方法忽略了音符的 ...

  9. [BZOJ]1023 cactus仙人掌图(SHOI2008)

    NOIP后的第一次更新嗯. Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在 ...

  10. [bzoj1143][CTSC2008]祭祀

    题意:给定一个n个点m条边的有向无环图,你要选出最多的点,并且满足任意两点之间都不存在通路.2)输出每个点选了它之后还是否有最优解.   n<=100 m<=1000 题解:每个点拆两个点 ...