现在有个糖果控制器,它的运行状态图如下:
我们要用java来实现这个糖果控制器。首先需要用一些实例变量来表示不同的状态:
我们的思路是创建一个糖果控制器类,它就像一个状态机,每个可能的操作都创建一个方法,在这些方法内部对当前状态进行判断,并做出相应的反应。
由于这并不难理解,所以直接上代码(有点长):
看起来这个系统是十分精密,无懈可击了。但是。。
需求有改变,糖果机要再曲柄转动后有10%可能性进入到赢家状态,这时候可以得到两颗糖果。
这下你有的忙了,你先要增加表示状态的实例变量,这还不算,还要在每个方法中增加赢家状态的判断和作出的相应反应,原来的系统将被改得面目全非了,如果以后再加入其他状态呢。。my god。。
之前接触过设计模式的你已经想到,要做一个可扩展性高的系统,要封装变化,要让不同状态的类解耦。
我们可以将每个状态的行为都放入一个类中,每个状态只要实现机器对应的动作就行了。糖果机在动作发生时委托给状态类。
我们创建一个状态的接口State,所有状态实现这个接口:
实现状态类:
糖果出售状态:
有25分钱状态:
糖果售罄状态留给大家去实现。
糖果机类:
看,各个方法的实现都委托给了当前状态,而当前状态在执行了委托的方法时,会做出相应的糖果机状态切换或者错误提示,这样糖果机在执行动作时,不管当前状态是什么,都执行当前状态的对应方法就行了,这样省去了冗长的判断语句。
这样我们让状态类”对修改关闭“,糖果机对”扩展开放“,可以随时加入新的状态类。
看看官方的定义:
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好想修改了它的状态。
该模式将状态封装成独立的类,并将动作委托到代表当前状态的对象。
类图:
context可以随时委托到状态对象的一个,当前状态可以在状态对象集合中游走改变,而context客户对于状态对象了解不多,甚至浑然不觉。我们可以将状态模式想成不用再context中放置大量判断语句的替代方案,并大大增加了代码的可扩展性。
我们的第一个版本中,最大缺点是将状态的转换放在状态类,使得状态类间产生了依赖。
但是为此产生了很多的类,这就是为了获取弹性代码而付出的代价。
别忘了我们还有要实现的赢家状态:
在糖果机中添加赢家状态。
赢家状态类:
当有”25分钱状态“下转动曲柄有10%可能进入赢家状态,所以在“有25分钱状态”代码做一点修改就可以了:
客户端程序: