经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
通俗易懂设计模式解析——状态模式
来源:cnblogs  作者:小世界的野孩子  时间:2019/10/14 10:43:26  对本文有异议

前言

  今天我们讲的是状态模式【State Pattern】、这个名字咋一看不好理解,但是仔细一想还是比较容易的。状态模式重点关注的是状态。状态又牵扯着什么呢?房屋的状态暂且可以分为出租、签订合同、退房。那么出租对应的是什么呢?出租状态代表可以租房。可以租房是一个行为了。所以不难理解的是状态模式关注的是状态的改变与行为的变化。

状态模式介绍

一、来由

  在软件系统中,经常状态的改变影响着行为的变化。例如房屋状态是出租既可以租房、出售既可以买卖房、不租售意味不可操作。那么如何避免对象操作和状态转换之间出现紧耦合呢?状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为正解决了此问题。

二、意图

  允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

三、案例图

 

四、状态模式代码示例

我们看下案例图中主要三个部分:

环境角色:包含保留了一个具体状态的实例、给出当前状态及调用方法。

抽象状态:定义接口、封装一个状态相对应的行为方法。

具体状态:实现具体状态对应的的具体对应行为。

我们继续看这个房屋的案例,针对房屋我们整理这么一个案例,租房然后签订合同。合同半年内退房无押金。租房时间达到半年退房可得押金。我们看下代码实现吧:

 

  1. namespace State_Pattern
  2. {
  3. /// <summary>
  4. /// 房屋对象类
  5. /// </summary>
  6. public class StatePattern
  7. {
  8. /// <summary>
  9. /// 房屋Id
  10. /// </summary>
  11. public int Id { get; set; }
  12. /// <summary>
  13. /// 房屋名称
  14. /// </summary>
  15. public string Name { get; set; }
  16. /// <summary>
  17. /// 租房时间/月
  18. /// </summary>
  19. public int Time { get; set; }
  20. /// <summary>
  21. /// 房屋状态
  22. /// </summary>
  23. public HouseState State { get; set; }
  24. /// <summary>
  25. /// 是否退押金
  26. /// </summary>
  27. public bool IsDeposit { get; set; }
  28. }
  29. /// <summary>
  30. /// 房屋出租状态枚举
  31. /// </summary>
  32. public enum HouseState
  33. {
  34. [Description("出租")]
  35. Lease =1,
  36. [Description("签订合同")]
  37. Leaseed = 2,
  38. [Description("退房")]
  39. Deposit = 3,
  40. }
  41. /// <summary>
  42. /// 环境角色
  43. /// </summary>
  44. public class Environmental
  45. {
  46. public State _state;
  47. /// <summary>
  48. /// 初始化房屋状态
  49. /// </summary>
  50. public Environmental()
  51. {
  52. this._state = new LeaseState();
  53. }
  54. public StatePattern _statePattern { get; set; }
  55. /// <summary>
  56. /// 获取房屋对象
  57. /// </summary>
  58. /// <param name="statePattern"></param>
  59. public void GetStatePattern(StatePattern statePattern,State state=null)
  60. {
  61. _statePattern = statePattern;
  62. if (state!=null)
  63. {
  64. _state = state;
  65. }
  66. }
  67. /// <summary>
  68. /// 更改状态方法
  69. /// </summary>
  70. /// <param name="state"></param>
  71. public void SetState(State state)
  72. {
  73. _state = state;
  74. }
  75. public void Show()
  76. {
  77. if (this._statePattern!=null)
  78. {
  79. _state.Handle(this);
  80. }
  81. else
  82. {
  83. Console.WriteLine("无可操作房屋!");
  84. }
  85. }
  86. }
  87. /// <summary>
  88. /// 抽象状态接口
  89. /// </summary>
  90. public interface State
  91. {
  92. void Handle(Environmental environmental);
  93. }
  94. /// <summary>
  95. /// 出租状态
  96. /// </summary>
  97. public class LeaseState : State
  98. {
  99. public void Handle(Environmental environmental)
  100. {
  101. //房屋出租
  102. if (environmental._statePattern.State==HouseState.Lease)
  103. {
  104. Console.WriteLine($"{environmental._statePattern.Name}房屋正在出租!");
  105. Console.WriteLine("如果觉得可以的话就签订租房合同!");
  106. environmental.SetState(new LeaseedState());
  107. environmental.Show();
  108. }
  109. }
  110. }
  111. /// <summary>
  112. /// 签订合同状态
  113. /// </summary>
  114. public class LeaseedState : State
  115. {
  116. public void Handle(Environmental environmental)
  117. {
  118. //后期办理退房手续
  119. if (environmental._statePattern.State == HouseState.Lease)
  120. {
  121. Console.WriteLine($"{environmental._statePattern.Name}签订租房合同!");
  122. environmental._statePattern.State = HouseState.Leaseed;
  123. environmental._statePattern.Time = 1;
  124. environmental.SetState(new DepositState());
  125. environmental.Show();
  126. }
  127. }
  128. }
  129. /// <summary>
  130. /// 退房有押金状态
  131. /// </summary>
  132. public class DepositState : State
  133. {
  134. public void Handle(Environmental environmental)
  135. {
  136. environmental._statePattern.IsDeposit = true;
  137. if (environmental._statePattern.State == HouseState.Leaseed && environmental._statePattern.Time < 6)
  138. {
  139. Console.WriteLine($"{environmental._statePattern.Name}如果现在退房的话是不能退押金的!");
  140. environmental._statePattern.IsDeposit = false;
  141. }
  142. else
  143. Console.WriteLine($"{environmental._statePattern.Name}如果现在退房的话是可以退押金的!");
  144. Console.WriteLine("考虑是否退房!");
  145. }
  146. }
  147. }

 

  1. namespace State_Pattern
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. //初始化房源信息
  8. List<StatePattern> statePatterns = new List<StatePattern>();
  9. statePatterns.Add(new StatePattern {Id=1,Name="房屋一",State=HouseState.Lease });
  10. Environmental environmental = new Environmental();
  11. //房屋一出租
  12. environmental.GetStatePattern(statePatterns.Where(x=>x.Id==1).FirstOrDefault());
  13. environmental.Show();
  14. //时间大于半年可退押金
  15. statePatterns[0].Time = 7;
  16. environmental.Show();
  17. }
  18. }
  19. }

  在上面的代码运行之后房屋一的状态在其对象内部发送了改变,从而行为也发送了变化。刚开始的正在出租改变成了签订合同出租之后。行为变化也从签订合同转变成了退房操作。 

使用场景及优缺点

一、使用场景

1、行为随着状态改变而改变的场景。

2、条件或分支语句的替代者。

二、优点

1、封装了状态及行为的转换规则。

2、在编写钱枚举出可能的状态,确定状态的种类。

3、方便状态的增加。只需要改变状态即可改变对象的行为。扩展性好。

4、可以多个环境一起共享一个状态对象,减少了对象个数。

三、缺点

1、状态模式会增加系统类和对象的个数

2、对开闭原则不友好。增加状态需要对那些负责状态转换的代码进行修改。否则的话无法转换到最新的状态。

3、状态模式的结构和实现都比较复杂,使用不当容易造成代码混乱及难理解。

总结

  状态模式到这里介绍完了,状态模式模式注重的状态在内部的改变自动改变其行为。对象看起来好像改变了它的类一样。抓住重点实现。第一个是状态的变化。第二个是状态变化引起的行为变化。第三个是在状态内部改变的。把状态的转换逻辑和状态对象放在一起。继而替换一个庞大的语句条件。


     时间抓起来说是金子,抓不住就是流水。

  C#设计模式系列目录

     欢迎大家扫描下方二维码,和我一起踏上设计模式的闯关之路吧!

  

原文链接:http://www.cnblogs.com/hulizhong/p/11662201.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号