概念
这个模式很好理解,一个实例的行为动作根据状态不同,而实现也不同,就比方说我们用打印机,有有纸状态,无纸状态,你要打印的时候,有纸状态就直接打印,无纸呢就发出警告。
程序的实现,我们第一直观当然是这样编码
if (hasPage) Print();
else ShowErrorMessage();
这样就是在每一个动作里加上状态的判断,当然没有问题,但问题是这样的,随着需求的更改,如果有新的状态出现的话,那么就不得不对所有的动作都进行更改,这个是烦琐的,而且是极容易出错,那么我们需要用到状态模式,uml图如下
将每个State设计为一个类,这样,对于用户来说,就根本不需要关心State内部的实现。
需求
现在有一个自动的糖果售卖机,投入硬币,按按钮,就出糖果。我们来分析下,糖果售卖机会有几种状态,1没投币,2投币了,3出糖果了,4糖果卖光了。ok,我们来画个简单的状态图
对于用户的动作要求,糖果机根据自己的状态来实现相应的回馈,参照概念的uml图,我们可以得出这里的context就是糖果机,State就是 NoMoney,HasMoney,Sold,SoldOut。 Handler有InsertMoney,EjectMoney,TurnCrank,Dispense等几个动作,
Nomoney的状态下,用户投币,则状态会随之改变为HasMoney。
HasMoney的状态下,用户转出糖果的按钮,则出糖果,状态改为Sold。
Sold的状态下,用户取出糖果,则判断剩余数量是否为空,空则SoldOut,否则状态改为NoMoney。
我们对于每个State实现所有的Handler,当有新的State出现时,直接添加一个新的State类就可以,不需要影响旧有代码
实现
首先是State接口和4个State类的实现
IState.cs:
NoMoneyState.cs:
HasMoneyState.cs:
SoldState.cs:
SoldOutState.cs:
然后是糖果机GumballMachine的实现,糖果机改变状态的方法这里采用工厂模式,把状态对象的创建分离出来。
GumballMachine.cs
枚举States.cs,这里列出所有的State
StateFactory.cs
ok,剩下的就是代码测试了
Program.cs
测试结果
insert the money
eject the money
pay first
insert the money
turn the crank
release a gum ball
对比
看到这里,是不是有种感觉,这不就是策略模式吗,都是把行为动作封装为一个接口,选择不同的行为动作来实现需求,不错,这是对的,可以这么说,策略模式和状态模式是双胞胎,极为相似,那2种模式并存意义何在呢,区别在哪,我觉得区别在于
策略模式的行为动作完全根据用户的需要,灵活改变。而各个行为之间没什么关联。想象下策略模式章节的鸭子的flybehavior,一个是flywithwing,一个是flynoway,一个会飞,一个不会飞,2者没有关联,会飞的鸭子不会变成不会飞的,不会飞的鸭子也不会变成会飞的。
状态模式行为动作的改变不是那么孤立,状态的处理会改变状态本身。重在状态的可转换。
注意
这章的连连看习题书里给出的答案是错误的,不知道大家有注意到没有,这个一定要注意,不要被迷惑。
书里原答案:
正确答案,用笔描红的为我更正的答案
下一篇: 《Head First Design Patterns》笔记十三:代理模式(Proxy Pattern)
上一篇: 《Head First Design Patterns》笔记十一:组合模式(Composite Pattern)