12 状态模式

状态模式(State)定义:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

UML类图

状态模式适用于要转换很多业务状态的场景。比如,Head First举的糖果机例子,

糖果机有“没有投币”、“有投币”、“售出糖果”、“糖果售罄”四种状态,并且有四种动作:“投入硬币”、“返回硬币”、“转动曲柄”、“发放糖果”。四种动作与四种状态之间的关系比较复杂,但上图可以清晰地表达出这种关系。

如果按照面向过程的实现方法,要表达出这种关系,需要一大堆的if else分支(4*4=16个),更麻烦的是,如果有新的状态加入,要修改的地方太多,违背了开放-封闭原则。

而采用状态模式可以部分地解决这个问题。

状态模式将每个状态封装成一个类,四种动作便成了类的四个方法,不同的类对这些方法有不同的实现,实现了状态类之间的自动切换。看起来很有《失控》中,那只用去中心化思维制造的机器昆虫,没有大脑,只为每只脚设定了动作规则,就可以完美运行。

代码如下:

先是规定了四种动作的接口:

1     interface State
2     {
3         void InsertQuarter();
4         void EjectQuarter();
5         void TurnQuarter();
6         void Dispense();
7     }

自带逻辑的四种状态如下(五种状态,这里多了赢家状态,赢家状态会一次吐出两颗糖果):

  1     class NoQuarterState:State
  2     {
  3         GumballMachine gumballMachine;
  4         public NoQuarterState(GumballMachine g)
  5         {
  6             gumballMachine = g;
  7         }
  8         public void InsertQuarter()
  9         {
 10             Console.WriteLine("You inserted a quarter");
 11             gumballMachine.SetState(gumballMachine.GetHasQuarterState());
 12         }
 13
 14         public void EjectQuarter()
 15         {
 16             Console.WriteLine("You haven‘t inserted a quarter");
 17         }
 18
 19         public void TurnQuarter()
 20         {
 21             Console.WriteLine("You turned,but there‘s no quarter");
 22         }
 23
 24         public void Dispense()
 25         {
 26             Console.WriteLine("You need to pay first");
 27         }
 28     }
 29
 30 //
 31 class HasQuarterState : State
 32     {
 33         Random randomWinner = new Random(DateTime.Now.Millisecond);
 34         GumballMachine gumballMachine;
 35         public HasQuarterState(GumballMachine g)
 36         {
 37             gumballMachine = g;
 38         }
 39         public void InsertQuarter()
 40         {
 41             Console.WriteLine("You can‘t insert another quarter");
 42         }
 43
 44         public void EjectQuarter()
 45         {
 46             Console.WriteLine("Quarter returned");
 47         }
 48
 49         public void TurnQuarter()
 50         {
 51
 52             Console.WriteLine("You turned");
 53             int randomNum = randomWinner.Next();
 54             if ((randomNum % 2 == 0) && (gumballMachine.GetCurrentCount() > 0))
 55             {
 56                 gumballMachine.SetState(gumballMachine.GetWinnerState());
 57             }
 58             else
 59             {
 60                 gumballMachine.SetState(gumballMachine.GetSoldState());
 61             }
 62
 63         }
 64
 65         public void Dispense()
 66         {
 67             Console.WriteLine("No gumball dispensed");
 68         }
 69     }
 70 //
 71 class SoldState : State
 72     {
 73         GumballMachine gumballMachine;
 74         public SoldState(GumballMachine g)
 75         {
 76             gumballMachine = g;
 77         }
 78         public void InsertQuarter()
 79         {
 80             Console.WriteLine("Please wait,we‘re already giving you a gumball");
 81         }
 82
 83         public void EjectQuarter()
 84         {
 85             Console.WriteLine("Sorry, you already turned the crank");
 86         }
 87
 88         public void TurnQuarter()
 89         {
 90             Console.WriteLine("Turning twice doesn‘t get you another gumball");
 91         }
 92
 93         public void Dispense()
 94         {
 95             gumballMachine.ReleaseBall();
 96             if (gumballMachine.GetCurrentCount() > 0)
 97             {
 98                 gumballMachine.SetState(gumballMachine.GetNoQuarterState());
 99             }
100             else
101             {
102                 Console.WriteLine("Oops,out of gumballs");
103                 gumballMachine.SetState(gumballMachine.GetSoldOutState());
104             }
105         }
106     }
107 //
108 class SoldOutState:State
109     {
110         GumballMachine gumballMachine;
111         public SoldOutState(GumballMachine g)
112         {
113             gumballMachine = g;
114         }
115         public void InsertQuarter()
116         {
117             Console.WriteLine("There is not gumballs");
118         }
119
120         public void EjectQuarter()
121         {
122             Console.WriteLine("You haven‘t inject a gumball");
123         }
124
125         public void TurnQuarter()
126         {
127             Console.WriteLine("Be quiet");
128         }
129
130         public void Dispense()
131         {
132             Console.WriteLine("No quarter anymore");
133         }
134     }

糖果机代码如下:

 1 class GumballMachine
 2     {
 3         State soldOutState;
 4         State noQuarterState;
 5         State hasQuarterState;
 6         State soldState;
 7         State winnerState;
 8         State state;
 9         int count = 0;
10         public GumballMachine(int numberGumballs)
11         {
12             soldOutState = new SoldOutState(this);
13             noQuarterState = new NoQuarterState(this);
14             hasQuarterState = new HasQuarterState(this);
15             soldState = new SoldState(this);
16             winnerState = new WinnerState(this);
17             this.count = numberGumballs;
18             if (numberGumballs > 0)
19             {
20                 state = noQuarterState;
21             }
22             else
23             {
24                 state = soldOutState;
25             }
26         }
27
28         public void InsertQuarter()
29         {
30             state.InsertQuarter();
31         }
32         public void EjectQuarter()
33         {
34             state.EjectQuarter();
35         }
36         public void TurnCrank()
37         {
38             state.TurnQuarter();
39             state.Dispense();
40         }
41         public void SetState(State s)
42         {
43             state = s;
44         }
45         public void ReleaseBall()
46         {
47             Console.WriteLine("A gumball comes rolling out the slot");
48             if (count != 0) count--;
49         }
50
51         public State GetSoldOutState()
52         {
53             return soldOutState;
54         }
55         public State GetNoQuarterState()
56         {
57             return noQuarterState;
58         }
59         public State GetHasQuarterState()
60         {
61             return hasQuarterState;
62         }
63         public State GetSoldState()
64         {
65             return soldState;
66         }
67         public State GetWinnerState()
68         {
69             return winnerState;
70         }
71         public int GetCurrentCount()
72         {
73             return count;
74         }
75     }

这里状态的转换由State类内部控制,但有可由Context就是这儿的Main函数中直接控制,可根据具体需求决定采用哪种方式。

使用状态模式通常会导致设计中类的数目大量增加。但相比很多if else分支来说,还是可取的,而且这些类并不对外可见。

状态模式与策略模式的区别:

两者的类图相同,但区别在于意图不同。

状态模式允许Context随着状态的改变而改变行为,但策略模式则用行为或算法来配置Context类。状态模式的状态变化逻辑已经内化,但策略模式使用哪种算法,可由外部决定。

时间: 2024-10-10 05:37:02

12 状态模式的相关文章

大话设计模式读书笔记--12.状态模式

定义 状态模式定义: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来改变了其类 消除庞大的条件分支,将特定状态的行为放入一个对象中 生活中:开灯和关灯是两个状态 模式结构 Context: 上下文环境,维护一个状态实例,定义当前的状态 State: 抽象状态类,定义一个接口,封装与Context的一个特定状态相关的行为 ConcreteState:具体状态.实现Context的一个特定状态相关的行为 代码实现 场景: 12店之前是休闲状态, 之后是忙碌状态 点击下载代码 特点及使用场

《大话设计模式》学习笔记12:状态模式

工作状态示例: 1.State: public abstract class State { public abstract void WriteProgram(Work work); } 2.ConcreteState(以ForenoonState.NoonState.SleepingState为例): public class ForenoonState:State { public override void WriteProgram(Work work) { if(work.Hour<1

设计模式12:状态模式

状态模式解决的是控制一个对象状态转移的表达式过于复杂的情况,把状态的判断逻辑转移表示到不同状态的一系列类中,可以把复杂的逻辑简化. 状态模式的好处是将特定状态的行为局部化,从而将不同状态的行为分割开来. 将特定状态的行为都放入一个对象中,由于与状态有关的代码都存在在具体的对象类中,因此定义新的子类可以很容易的实现增加新的状态和转换. uml图: State及其子类 public abstract class State { public abstract void writeProgram(Wo

2018/12/07《大话设计模式》【状态模式】

< Forever 吴建豪>洗脑~ 1:什么是状态模式? - 定义:当一个对象的内在状态改变时,允许改变其行为,这个对象看起开像是改了其类. - 哎~又来了句让人听不明白的定义...... - 看一段代码来理解吧 class A { private $state; public function __construct($state) { $this->state = $state; } public function echo() { if ($this->state == 'A

大量逻辑判断优化的思路——责任链模式复习总结及其和状态模式对比

俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的总结知识点如下: 责任链模式概念和例子 使用的条件 和状态模式的比较分析 责任链的优缺点 纯的责任链和不纯的责任链 javax.servlet.Filter#doFilter()方法源码分析 基于AOP思想,模拟一个拦截器 前面说了一个状态模式,总结过程中发现和这个责任链的使用场景很类似,都是为了解耦大量复杂业务逻辑判断的,那么他们有什么不同呢?回忆状态模式——状态模式允许通过改变对象的内部状态而改变对象自身的行为,这个对象

23状态模式

 1状态模式的核心内容是: A:状态类 B:工作类 2状态模式的作用:通过状态值自动跳转到要执行的类. 3状态模式具体描述 状态模式:状态模式允许一个对象在其内部状态改变的时候改变行为. 这个对象看上去象是改变了它的类一样.状态模式把所研究的对象的行 为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的 一个子类.状态模式的意图是让一个对象在其内部状态改变的时候, 其行为也随之改变.状态模式需要对每一个系统可能取得的状态创立一个状态类的 子类.当系统的状态变化时,系统便改变所选的子

状态模式

使用场景 业务中比较多的状态,不同状态下需要做的事情不同.这样,每个步骤中都需要判断一下当前属于什么状态,状态过滤完成以后对相应的状态作出处理.当前状态执行完成以后,可能需要根据条件进入下一个状态(可能是下一个状态,可能是上一个状态,可能是终止或者回到初始状态等).这种逻辑判断完以后一般都会出现比较多的if...else或者switch...case.最可怕的是后面如果加入一个状态或者修改状态相应的处理动作,这样就比较麻烦了.状态模式通过把状态拆分成不同的状态类来拆解条件.这样,在以后改变需求时

设计模式-状态模式(State Pattern)

本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/ 状态模式简介 状态模式允许一个对象在其内部状态改变的时候改变它的行为,他的内部会存着好几种状态,在当前状态发生变化是,这个对象执行和之前相同的操作也会有不同的作用效果. 状态模式的定义和基本结构 定义:状态模式允许一个对象在其内部状态改变的时候改变它的行为,就像变成了另一个对象一样. 一张来自<Head First>的结构图 Context:这个类里面包含了很多种状态类,当前状态不同时,这个

策略模式的孪生兄弟——对状态模式的深度复习总结

俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的总结知识点如下: 和策略模式的比较 状态模式概念和例子 应用场景 责任链模式和状态模式对比 一种代码优化的思路 java.util.Iterator里也有状态模式的影子 状态模式的优缺点 有限状态机及其应用 前面有总结——策略模式,之前早就觉得策略和状态设计模式有一些相似…… 接口的常用用法都有什么?策略设计模式复习总结 我知道策略模式是对象的行为模式,其实就是对一系列级别平等的算法的封装,它不关心算法实现,让客户端去动态的