一台糖果机,支持n种操作,譬如:投入硬币、退还硬币、转动曲柄、填充糖果……
而不同状态下不同操作返回的内容不一样。下面是它的状态转换图:
如何实现它的转换呢?
这是一个不使用模式的例子:
-
package state. old;
-
-
public class OldCandyMachine {
-
-
private int state;
-
public static int EMPTY_WORK_STATE = 0;
-
public static int FREE_WORK_STATE = 1;
-
public static int HAVE_MONEY_WORK_STATE = 2;
-
-
private int candyCount;
-
-
public OldCandyMachine ( int candyCount ) {
-
this. candyCount = candyCount;
-
if (candyCount> 0 ) {
-
state = OldCandyMachine. FREE_WORK_STATE;
-
} else {
-
state = OldCandyMachine. EMPTY_WORK_STATE;
-
}
-
}
-
-
public int getCandyCount ( ) {
-
return candyCount;
-
}
-
-
public void setCandyCount ( int candyCount ) {
-
this. candyCount = candyCount;
-
}
-
-
public boolean fillCandy ( int candyCount ) {
-
if (state == OldCandyMachine. EMPTY_WORK_STATE ) {
-
this. candyCount = candyCount;
-
this. state = OldCandyMachine. FREE_WORK_STATE;
-
return true;
-
}
-
return false;
-
}
-
-
public boolean inputMoney ( ) {
-
if ( state == OldCandyMachine. FREE_WORK_STATE ) {
-
state = OldCandyMachine. HAVE_MONEY_WORK_STATE;
-
return true;
-
}
-
if ( state == OldCandyMachine. EMPTY_WORK_STATE ) {
-
return false;
-
}
-
if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
-
return false;
-
}
-
return false;
-
}
-
-
public boolean returnMoney ( ) {
-
if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
-
state = OldCandyMachine. FREE_WORK_STATE;
-
return true;
-
}
-
return false;
-
}
-
-
public boolean turn ( ) {
-
if ( state == OldCandyMachine. HAVE_MONEY_WORK_STATE ) {
-
state = OldCandyMachine. FREE_WORK_STATE;
-
outCandy ( );
-
return true;
-
}
-
return false;
-
}
-
-
public void outCandy ( ) {
-
candyCount--;
-
if (candyCount== 0 ) {
-
state = OldCandyMachine. EMPTY_WORK_STATE;
-
}
-
}
-
-
}
在这样的代码下,如果我们要增加一个状态,该修改多少代码?
它的条件语句过多,容易出错,状态转换并不明显,
下面,我们尝试着用状态模式来重构。
[CandyMachine]使用了状态模式的、崭新的糖果机
-
package state;
-
-
import state.workstate.EmptyWorkState;
-
import state.workstate.FreeWorkState;
-
import state.workstate.WorkState;
-
-
-
public class CandyMachine {
-
-
private WorkState workState;
-
-
private int candyCount;
-
-
public CandyMachine ( int candyCount ) {
-
this. candyCount = candyCount;
-
if (candyCount> 0 ) {
-
workState = new FreeWorkState ( this );
-
} else {
-
workState = new EmptyWorkState ( this );
-
}
-
}
-
-
public int getCandyCount ( ) {
-
return candyCount;
-
}
-
-
public void setCandyCount ( int candyCount ) {
-
this. candyCount = candyCount;
-
}
-
-
public WorkState getWorkState ( ) {
-
return workState;
-
}
-
-
public void setWorkState (WorkState workState ) {
-
this. workState = workState;
-
}
-
-
public boolean fillCandy ( int candyCount ) {
-
if (workState. fillCandy ( ) ) {
-
this. candyCount = candyCount;
-
return true;
-
}
-
return false;
-
}
-
-
public boolean inputMoney ( ) {
-
return workState. inputMoney ( );
-
}
-
-
public boolean returnMoney ( ) {
-
return workState. returnMoney ( );
-
}
-
-
public boolean turn ( ) {
-
if (workState. turn ( ) ) {
-
outCandy ( );
-
return true;
-
}
-
return false;
-
}
-
-
public void outCandy ( ) {
-
candyCount--;
-
if (candyCount== 0 ) {
-
this. setWorkState ( new EmptyWorkState ( this ) );
-
}
-
}
-
-
}
[WorkState]糖果机工作状态:抽象类,也可定义成接口,在这里约定要实现的方法(糖果机能进行的操作)。
-
package state. workstate;
-
-
import state.CandyMachine;
-
-
-
public abstract class WorkState {
-
-
public CandyMachine machine;
-
-
public WorkState (CandyMachine machine ) {
-
this. machine = machine;
-
}
-
-
public abstract boolean fillCandy ( );
-
-
public abstract boolean inputMoney ( );
-
-
public abstract boolean returnMoney ( );
-
-
public abstract boolean turn ( );
-
-
}
[EmptyWorkState]糖果售罄的糖果机工作状态
-
package state. workstate;
-
-
import state.CandyMachine;
-
-
-
public class EmptyWorkState extends WorkState {
-
-
public EmptyWorkState (CandyMachine machine ) {
-
super (machine );
-
}
-
-
@Override
-
public boolean fillCandy ( ) {
-
machine. setWorkState ( new FreeWorkState (machine ) );
-
return true;
-
}
-
-
@Override
-
public boolean inputMoney ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean returnMoney ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean turn ( ) {
-
return false;
-
}
-
-
}
[FreeWorkState]空闲的糖果机工作状态
-
package state. workstate;
-
-
import state.CandyMachine;
-
-
-
public class FreeWorkState extends WorkState {
-
-
public FreeWorkState (CandyMachine machine ) {
-
super (machine );
-
}
-
-
@Override
-
public boolean fillCandy ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean inputMoney ( ) {
-
machine. setWorkState ( new HaveMoneyWorkState (machine ) );
-
return true;
-
}
-
-
@Override
-
public boolean returnMoney ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean turn ( ) {
-
return false;
-
}
-
-
}
[HaveMoneyWorkState]已填充硬币后的糖果机工作状态
-
package state. workstate;
-
-
import state.CandyMachine;
-
-
-
public class HaveMoneyWorkState extends WorkState {
-
-
public HaveMoneyWorkState (CandyMachine machine ) {
-
super (machine );
-
}
-
-
@Override
-
public boolean fillCandy ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean inputMoney ( ) {
-
return false;
-
}
-
-
@Override
-
public boolean returnMoney ( ) {
-
machine. setWorkState ( new FreeWorkState (machine ) );
-
return true;
-
}
-
-
@Override
-
public boolean turn ( ) {
-
machine. setWorkState ( new FreeWorkState (machine ) );
-
return true;
-
}
-
-
}
以及它的UT
-
package state;
-
-
import state.old.OldCandyMachine;
-
import state.workstate.*;
-
import junit.framework.TestCase;
-
-
public class TestCandyMachineState extends TestCase {
-
-
public void testOldCandyMachine ( ) {
-
OldCandyMachine machine = new OldCandyMachine ( 0 );
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. fillCandy ( 3 ) ); // 此处对糖果机填充:状态已经改变
-
-
assertEquals (machine. getCandyCount ( ), 3 ); // 填充三个
-
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. inputMoney ( ) ); // 此处将钱放入糖果机:状态已经改变
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertTrue (machine. returnMoney ( ) ); // 此处从糖果机退钱:状态已经改变
-
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. inputMoney ( ) ); // 此处将钱放入糖果机:状态已经改变
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertTrue (machine. turn ( ) ); // 此处使用糖果机:状态已经改变
-
-
assertEquals (machine. getCandyCount ( ), 2 ); // 使用过一次后数量-1
-
}
-
-
public void testCandyMachine ( ) {
-
CandyMachine machine = new CandyMachine ( 0 );
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. getWorkState ( ) instanceof EmptyWorkState );
-
assertTrue (machine. fillCandy ( 3 ) ); // 此处对糖果机填充:状态已经改变
-
assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
-
-
assertEquals (machine. getCandyCount ( ), 3 ); // 填充三个
-
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
-
assertTrue (machine. inputMoney ( ) ); // 此处将钱放入糖果机:状态已经改变
-
assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
-
assertTrue (machine. returnMoney ( ) ); // 此处从糖果机退钱:状态已经改变
-
assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
-
-
assertFalse (machine. returnMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertFalse (machine. turn ( ) );
-
assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
-
assertTrue (machine. inputMoney ( ) ); // 此处将钱放入糖果机:状态已经改变
-
assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
-
-
assertFalse (machine. inputMoney ( ) );
-
assertFalse (machine. fillCandy ( 3 ) );
-
assertTrue (machine. getWorkState ( ) instanceof HaveMoneyWorkState );
-
assertTrue (machine. turn ( ) ); // 此处使用糖果机:状态已经改变
-
assertTrue (machine. getWorkState ( ) instanceof FreeWorkState );
-
-
assertEquals (machine. getCandyCount ( ), 2 ); // 使用过一次后数量-1
-
}
-
-
}
状态模式(State)
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
适用性
一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。S t a t e模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
让我们回过头来看看策略模式:
单从UML图看来,它们之间似乎没有什么不一样……
再看看它的意图:
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
注意到了吗?
策略模式的目的是可以在运行时改变行为,让设计更有弹性;
而在状态模式中,“改变行为”这件事则是建立在它的方案中的,状态在状态对象集合中游走改变,它的对象行为也会跟着改变,可是使用对象的client却可以完全不了解它。
最后用一段来自《Head First 设计模式》的话:
一般来说,我们把策略模式想成是除了继承之外的一种弹性替代方案。如果你使用继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难。有了策略模式,你可以通过组合不同的对象来改变行为。
我们把状态模式想成是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。