调侃《First head 设计模式》之状态模式篇

来源:互联网 发布:北京淘宝供货商 编辑:程序博客网 时间:2024/05/16 01:04

     现在有个糖果控制器,它的运行状态图如下:

    

    我们要用java来实现这个糖果控制器。首先需要用一些实例变量来表示不同的状态:

    

    我们的思路是创建一个糖果控制器类,它就像一个状态机,每个可能的操作都创建一个方法,在这些方法内部对当前状态进行判断,并做出相应的反应。

    由于这并不难理解,所以直接上代码(有点长):

    

      

     

     看起来这个系统是十分精密,无懈可击了。但是。。

     需求有改变,糖果机要再曲柄转动后有10%可能性进入到赢家状态,这时候可以得到两颗糖果。

     这下你有的忙了,你先要增加表示状态的实例变量,这还不算,还要在每个方法中增加赢家状态的判断和作出的相应反应,原来的系统将被改得面目全非了,如果以后再加入其他状态呢。。my god。。

     之前接触过设计模式的你已经想到,要做一个可扩展性高的系统,要封装变化,要让不同状态的类解耦。

     我们可以将每个状态的行为都放入一个类中,每个状态只要实现机器对应的动作就行了。糖果机在动作发生时委托给状态类。

     我们创建一个状态的接口State,所有状态实现这个接口:

    

   实现状态类:

   

    糖果出售状态:

     

     

      有25分钱状态:

      

     糖果售罄状态留给大家去实现。

     糖果机类:

     

      看,各个方法的实现都委托给了当前状态,而当前状态在执行了委托的方法时,会做出相应的糖果机状态切换或者错误提示,这样糖果机在执行动作时,不管当前状态是什么,都执行当前状态的对应方法就行了,这样省去了冗长的判断语句。

      这样我们让状态类”对修改关闭“,糖果机对”扩展开放“,可以随时加入新的状态类。

      

      看看官方的定义:

      状态模式允许对象在内部状态改变时改变它的行为,对象看起来好想修改了它的状态。

      该模式将状态封装成独立的类,并将动作委托到代表当前状态的对象。

      类图:

     

    context可以随时委托到状态对象的一个,当前状态可以在状态对象集合中游走改变,而context客户对于状态对象了解不多,甚至浑然不觉。我们可以将状态模式想成不用再context中放置大量判断语句的替代方案,并大大增加了代码的可扩展性。

     我们的第一个版本中,最大缺点是将状态的转换放在状态类,使得状态类间产生了依赖。

     但是为此产生了很多的类,这就是为了获取弹性代码而付出的代价。

     

     别忘了我们还有要实现的赢家状态:

     在糖果机中添加赢家状态。

     

    赢家状态类:

     

     当有”25分钱状态“下转动曲柄有10%可能进入赢家状态,所以在“有25分钱状态”代码做一点修改就可以了:

     

     客户端程序:

     

2 0