糖果机的状态转换。。

一台糖果机,支持n种操作,譬如:投入硬币、退还硬币、转动曲柄、填充糖果……
而不同状态下不同操作返回的内容不一样。下面是它的状态转换图:

如何实现它的转换呢?
这是一个不使用模式的例子:

  1. package state. old;
  2.  
  3. public class OldCandyMachine {
  4.        
  5.         private int state;
  6.         public static int EMPTY_WORK_STATE = 0;
  7.         public static int FREE_WORK_STATE = 1;
  8.         public static int HAVE_MONEY_WORK_STATE = 2;
  9.        
  10.         private int candyCount;
  11.  
  12.         public OldCandyMachine ( int candyCount ) {
  13.                 this. candyCount = candyCount;
  14.                 if (candyCount> 0 ) {
  15.                         state = OldCandyMachine. FREE_WORK_STATE;
  16.                 } else {
  17.                         state = OldCandyMachine. EMPTY_WORK_STATE;
  18.                 }
  19.         }
  20.        
  21.         public int getCandyCount ( ) {
  22.                 return candyCount;
  23.         }
  24.        
  25.         public void setCandyCount ( int candyCount ) {
  26.                 this. candyCount = candyCount;
  27.         }
  28.        
  29.         public boolean fillCandy ( int candyCount ) {
  30.                 if (state == OldCandyMachine. EMPTY_WORK_STATE ) {
  31.                         this. candyCount = candyCount;
  32.                         this. state = OldCandyMachine. FREE_WORK_STATE;
  33.                         return true;
  34.                 }
  35.                 return false;
  36.         }
  37.        
  38.         public boolean inputMoney ( ) {
  39.                 if ( state == OldCandyMachine. FREE_WORK_STATE ) {
  40.                         state = OldCandyMachine. HAVE_MONEY_WORK_STATE;
  41.                         return true;
  42.                 }
  43.                 if ( state == OldCandyMachine. EMPTY_WORK_STATE ) {
  44.                         System. out. println ( "糖果机里没有糖果!" );
  45.                         return false;
  46.                 }
  47.                 if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
  48.                         System. out. println ( "糖果机里已经有钱了!" );
  49.                         return false;
  50.                 }
  51.                 return false;
  52.         }
  53.        
  54.         public boolean returnMoney ( ) {
  55.                 if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
  56.                         state = OldCandyMachine. FREE_WORK_STATE;
  57.                         return true;
  58.                 }
  59.                 return false;
  60.         }
  61.        
  62.         public boolean turn ( ) {
  63.                 if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
  64.                         state = OldCandyMachine. FREE_WORK_STATE;                       
  65.                         outCandy ( );
  66.                         return true;
  67.                 }
  68.                 return false;
  69.         }
  70.        
  71.         public void outCandy ( ) {
  72.                 System. out. println ( "糖果机弹出了糖果!" );
  73.                 candyCount--;
  74.                 if (candyCount== 0 ) {
  75.                         state = OldCandyMachine. EMPTY_WORK_STATE;
  76.                 }
  77.         }
  78.  
  79. }

 在这样的代码下,如果我们要增加一个状态,该修改多少代码?
它的条件语句过多,容易出错,状态转换并不明显,
下面,我们尝试着用状态模式来重构。

[CandyMachine]使用了状态模式的、崭新的糖果机

  1. package state;
  2.  
  3. import state.workstate.EmptyWorkState;
  4. import state.workstate.FreeWorkState;
  5. import state.workstate.WorkState;
  6.  
  7.  
  8. public class CandyMachine {
  9.        
  10.         private WorkState workState;
  11.        
  12.         private int candyCount;
  13.  
  14.         public CandyMachine ( int candyCount ) {
  15.                 this. candyCount = candyCount;
  16.                 if (candyCount> 0 ) {
  17.                         workState = new FreeWorkState ( this );
  18.                 } else {
  19.                         workState = new EmptyWorkState ( this );
  20.                 }
  21.         }
  22.        
  23.         public int getCandyCount ( ) {
  24.                 return candyCount;
  25.         }
  26.        
  27.         public void setCandyCount ( int candyCount ) {
  28.                 this. candyCount = candyCount;
  29.         }
  30.  
  31.         public WorkState getWorkState ( ) {
  32.                 return workState;
  33.         }
  34.  
  35.         public void setWorkState (WorkState workState ) {
  36.                 this. workState = workState;
  37.         }
  38.        
  39.         public boolean fillCandy ( int candyCount ) {
  40.                 if (workState. fillCandy ( ) ) {
  41.                         this. candyCount = candyCount;
  42.                         return true;
  43.                 }
  44.                 return false;
  45.         }
  46.        
  47.         public boolean inputMoney ( ) {
  48.                 return workState. inputMoney ( );
  49.         }
  50.        
  51.         public boolean returnMoney ( ) {
  52.                 return workState. returnMoney ( );
  53.         }
  54.        
  55.         public boolean turn ( ) {
  56.                 if (workState. turn ( ) ) {
  57.                         outCandy ( );
  58.                         return true;
  59.                 }
  60.                 return false;
  61.         }
  62.        
  63.         public void outCandy ( ) {
  64.                 System. out. println ( "糖果机弹出了糖果!" );
  65.                 candyCount--;
  66.                 if (candyCount== 0 ) {
  67.                         this. setWorkState ( new EmptyWorkState ( this ) );
  68.                 }
  69.         }
  70.        
  71. }

 [WorkState]糖果机工作状态:抽象类,也可定义成接口,在这里约定要实现的方法(糖果机能进行的操作)。

  1. package state. workstate;
  2.  
  3. import state.CandyMachine;
  4.  
  5.  
  6. public abstract class WorkState {
  7.        
  8.         public CandyMachine machine;
  9.        
  10.         public WorkState (CandyMachine machine ) {
  11.                 this. machine = machine;
  12.         }
  13.        
  14.         public abstract boolean fillCandy ( );
  15.        
  16.         public abstract boolean inputMoney ( );
  17.        
  18.         public abstract boolean returnMoney ( );
  19.        
  20.         public abstract boolean turn ( );
  21.  
  22. }

 [EmptyWorkState]糖果售罄的糖果机工作状态

  1. package state. workstate;
  2.  
  3. import state.CandyMachine;
  4.  
  5.  
  6. public class EmptyWorkState extends WorkState {
  7.  
  8.         public EmptyWorkState (CandyMachine machine ) {
  9.                 super (machine );
  10.         }
  11.  
  12.         @Override
  13.         public boolean fillCandy ( ) {
  14.                 System. out. println ( "填满糖果机!" );
  15.                 machine. setWorkState ( new FreeWorkState (machine ) );
  16.                 return true;
  17.         }
  18.  
  19.         @Override
  20.         public boolean inputMoney ( ) {
  21.                 System. out. println ( "糖果机里没有糖果!" );
  22.                 return false;
  23.         }
  24.  
  25.         @Override
  26.         public boolean returnMoney ( ) {
  27.                 System. out. println ( "糖果机里没有钱!" );
  28.                 return false;
  29.         }
  30.  
  31.         @Override
  32.         public boolean turn ( ) {
  33.                 System. out. println ( "糖果机里没有糖果!" );
  34.                 return false;
  35.         }
  36.  
  37. }

 [FreeWorkState]空闲的糖果机工作状态

  1. package state. workstate;
  2.  
  3. import state.CandyMachine;
  4.  
  5.  
  6. public class FreeWorkState extends WorkState {
  7.  
  8.         public FreeWorkState (CandyMachine machine ) {
  9.                 super (machine );
  10.         }
  11.  
  12.         @Override
  13.         public boolean fillCandy ( ) {
  14.                 System. out. println ( "糖果机已满!" );
  15.                 return false;
  16.         }
  17.  
  18.         @Override
  19.         public boolean inputMoney ( ) {
  20.                 System. out. println ( "钱已投入糖果机!" );
  21.                 machine. setWorkState ( new HaveMoneyWorkState (machine ) );
  22.                 return true;
  23.         }
  24.  
  25.         @Override
  26.         public boolean returnMoney ( ) {
  27.                 System. out. println ( "糖果机中没有钱!" );
  28.                 return false;
  29.         }
  30.  
  31.         @Override
  32.         public boolean turn ( ) {
  33.                 System. out. println ( "还没有投币不能使用!" );
  34.                 return false;
  35.         }
  36.  
  37. }

 [HaveMoneyWorkState]已填充硬币后的糖果机工作状态

  1. package state. workstate;
  2.  
  3. import state.CandyMachine;
  4.  
  5.  
  6. public class HaveMoneyWorkState extends WorkState {
  7.  
  8.         public HaveMoneyWorkState (CandyMachine machine ) {
  9.                 super (machine );
  10.         }
  11.  
  12.         @Override
  13.         public boolean fillCandy ( ) {
  14.                 System. out. println ( "糖果机已满!" );
  15.                 return false;
  16.         }
  17.  
  18.         @Override
  19.         public boolean inputMoney ( ) {
  20.                 System. out. println ( "糖果机已有钱!" );
  21.                 return false;
  22.         }
  23.  
  24.         @Override
  25.         public boolean returnMoney ( ) {
  26.                 System. out. println ( "糖果机已退钱!" );
  27.                 machine. setWorkState ( new FreeWorkState (machine ) );
  28.                 return true;
  29.         }
  30.  
  31.         @Override
  32.         public boolean turn ( ) {
  33.                 System. out. println ( "使用糖果机!" );
  34.                 machine. setWorkState ( new FreeWorkState (machine ) );
  35.                 return true;
  36.         }
  37.  
  38. }

以及它的UT

  1. package state;
  2.  
  3. import state.old.OldCandyMachine;
  4. import state.workstate.*;
  5. import junit.framework.TestCase;
  6.  
  7. public class TestCandyMachineState extends TestCase {
  8.        
  9.         public void testOldCandyMachine ( ) {
  10.                 OldCandyMachine machine = new OldCandyMachine ( 0 );
  11.                
  12.                 assertFalse (machine. inputMoney ( ) );
  13.                 assertFalse (machine. returnMoney ( ) );
  14.                 assertFalse (machine. turn ( ) );
  15.                 assertTrue (machine. fillCandy ( 3 ) );        //     此处对糖果机填充:状态已经改变
  16.                
  17.                 assertEquals (machine. getCandyCount ( ), 3 );        // 填充三个
  18.                
  19.                 assertFalse (machine. returnMoney ( ) );
  20.                 assertFalse (machine. fillCandy ( 3 ) );
  21.                 assertFalse (machine. turn ( ) );
  22.                 assertTrue (machine. inputMoney ( ) );        //     此处将钱放入糖果机:状态已经改变
  23.                
  24.                 assertFalse (machine. inputMoney ( ) );
  25.                 assertFalse (machine. fillCandy ( 3 ) );
  26.                 assertTrue (machine. returnMoney ( ) );      //    此处从糖果机退钱:状态已经改变
  27.                
  28.                 assertFalse (machine. returnMoney ( ) );
  29.                 assertFalse (machine. fillCandy ( 3 ) );
  30.                 assertFalse (machine. turn ( ) );
  31.                 assertTrue (machine. inputMoney ( ) );        //     此处将钱放入糖果机:状态已经改变
  32.                
  33.                 assertFalse (machine. inputMoney ( ) );
  34.                 assertFalse (machine. fillCandy ( 3 ) );
  35.                 assertTrue (machine. turn ( ) );                //   此处使用糖果机:状态已经改变
  36.                
  37.                 assertEquals (machine. getCandyCount ( ), 2 );        //      使用过一次后数量-1
  38.         }
  39.        
  40.         public void testCandyMachine ( ) {
  41.                 CandyMachine machine = new CandyMachine ( 0 );
  42.                
  43.                 assertFalse (machine. inputMoney ( ) );
  44.                 assertFalse (machine. returnMoney ( ) );
  45.                 assertFalse (machine. turn ( ) );
  46.                 assertTrue (machine. getWorkState ( ) instanceof EmptyWorkState );
  47.                 assertTrue (machine. fillCandy ( 3 ) );        //     此处对糖果机填充:状态已经改变
  48.                 assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
  49.                
  50.                 assertEquals (machine. getCandyCount ( ), 3 );        // 填充三个
  51.                
  52.                 assertFalse (machine. returnMoney ( ) );
  53.                 assertFalse (machine. fillCandy ( 3 ) );
  54.                 assertFalse (machine. turn ( ) );
  55.                 assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
  56.                 assertTrue (machine. inputMoney ( ) );        //     此处将钱放入糖果机:状态已经改变
  57.                 assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
  58.                
  59.                 assertFalse (machine. inputMoney ( ) );
  60.                 assertFalse (machine. fillCandy ( 3 ) );
  61.                 assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
  62.                 assertTrue (machine. returnMoney ( ) );      //    此处从糖果机退钱:状态已经改变
  63.                 assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
  64.                
  65.                 assertFalse (machine. returnMoney ( ) );
  66.                 assertFalse (machine. fillCandy ( 3 ) );
  67.                 assertFalse (machine. turn ( ) );
  68.                 assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
  69.                 assertTrue (machine. inputMoney ( ) );        //     此处将钱放入糖果机:状态已经改变
  70.                 assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
  71.                
  72.                 assertFalse (machine. inputMoney ( ) );
  73.                 assertFalse (machine. fillCandy ( 3 ) );
  74.                 assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
  75.                 assertTrue (machine. turn ( ) );                //   此处使用糖果机:状态已经改变
  76.                 assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
  77.                
  78.                 assertEquals (machine. getCandyCount ( ), 2 );        //      使用过一次后数量-1
  79.         }
  80.  
  81. }

 

状态模式(State)


允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

适用性
一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。S t a t e模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

让我们回过头来看看策略模式

单从UML图看来,它们之间似乎没有什么不一样……

再看看它的意图:

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

注意到了吗?
策略模式的目的是可以在运行时改变行为,让设计更有弹性;
而在状态模式中,“改变行为”这件事则是建立在它的方案中的,状态在状态对象集合中游走改变,它的对象行为也会跟着改变,可是使用对象的client却可以完全不了解它。

最后用一段来自《Head First 设计模式》的话:

  一般来说,我们把策略模式想成是除了继承之外的一种弹性替代方案。如果你使用继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难。有了策略模式,你可以通过组合不同的对象来改变行为。
我们把状态模式想成是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值