深入浅出设计模式-012:状态模式(State Pattern)
一:状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像改变了它的类。
模式将状态封装成独立的类,并将动作委托到代表当前状态的对象。
二:糖果机
首先,定义一个STATE接口,在这个接口内,糖果机的每个动作都有一个对应的方法。
然后为机器中的每个状态实现状态类。这些类将负责在对应的状态下进行机器的行为。
最要,我们要摆脱旧的条件代码,取而代之的方式是将动作委托到状态类。
让每一个状态“对修改关闭”,让糖果机“多扩展开发”,这样可以加入新的状态类
class GumballMachine//CONTEXT{
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State state;
int count = 0;
public GumballMachine(int numberGumballs){
this.soldOutState = new SoldOutState(this);
this.noQuarterState = new NoQuarterState(this);
this.hasQuarterState = new HasQuarterState(this);
this.soldState = new SoldState(this);
this.count = numberGumballs;
if (numberGumballs > 0){
this.state = this.noQuarterState;
}
else{
this.state = this.soldOutState;
}
}
public State StateOfMachine {
get { return state; }
set { state = value; }
}
public int Count{
get { return count; }
set { count = value; }
}
public State getSoldOutState{
get { return soldOutState; }
}
public State getNoQuarterState{
get { return noQuarterState; }
}
public State getHasQuarterState{
get { return hasQuarterState; }
}
public State getSoldState{
get { return soldState; }
}
public void insertQuarter(){
state.insertQuarter();
}
public void ejectQuarter(){
state.ejectQuarter();
}
public void turnCrank(){
state.turnCrank();
}
public void dispense(){
state.dispense();
}
public void releaseBall(){
if (count != 0)
count -= 1;
}
}
interface State{
//操作糖果机的四个动作:插入硬币,退回硬币,转动手柄,出糖果
//糖果机的四个状态:没有硬币,有硬币,售出糖果,糖果售罄
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispense();
}
class NoQuarterState : State{
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine){
this.gumballMachine = gumballMachine;
}
public void insertQuarter() {
gumballMachine.StateOfMachine = gumballMachine.getHasQuarterState;
}
public void ejectQuarter() { }
public void turnCrank() { }
public void dispense() { }
}
class HasQuarterState : State{
GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine){
this.gumballMachine = gumballMachine;
}
public void insertQuarter() { }
public void ejectQuarter() {
gumballMachine.StateOfMachine = gumballMachine.getNoQuarterState;
}
public void turnCrank(){
gumballMachine.StateOfMachine = gumballMachine.getSoldState;
}
public void dispense() { }
}
class SoldState : State{
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine){
this.gumballMachine = gumballMachine;
}
public void insertQuarter() { }
public void ejectQuarter() { }
public void turnCrank() { }
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.Count > 0){
gumballMachine.StateOfMachine = gumballMachine.getNoQuarterState;
}
else{
gumballMachine.StateOfMachine = gumballMachine.getSoldOutState;
}
}
}
class SoldOutState : State{
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine){
this.gumballMachine = gumballMachine;
}
public void insertQuarter() { }
public void ejectQuarter() { }
public void turnCrank() { }
public void dispense() { }
}
static void Main(string[] args)
{
GumballMachine gumballMachine = new GumballMachine(5);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}
三:在状态机中加入新的状态,即在出糖果时,1/10的概率出2个。加起来就很方便了
可以考虑把WinnerState类的作用直接放入HasQuarterState盅。
这样没有符合“一个类,一个责任。”
1: 构建状态类
class WinnerState : State
{
GumballMachine gumballMachine;
public WinnerState(GumballMachine gumballMachine)
{
this.gumballMachine = gumballMachine;
}
public void insertQuarter() { }
public void ejectQuarter() { }
public void turnCrank() { }
public void dispense()
{
gumballMachine.releaseBall();
if (gumballMachine.Count == 0)
{
gumballMachine.StateOfMachine = gumballMachine.getSoldOutState;
}
else
{
gumballMachine.releaseBall();
if (gumballMachine.Count == 0)
{
gumballMachine.StateOfMachine = gumballMachine.getSoldOutState;
}
}
}
}
2: 在GumballMachine中加入状态类
class GumballMachine//CONTEXT
{
State winnerState;
}
3: 修改HasQuarterState,有这个状态触发
class HasQuarterState : State
{
Random rand = new Random(DateTime.Now.Second);
public void turnCrank()
{
int winner = rand.Next(10);
if (winner == 0 && gumballMachine.Count > 1)
{
gumballMachine.StateOfMachine = gumballMachine.getWinnerState;
}
else
{
gumballMachine.StateOfMachine = gumballMachine.getSoldState;
}
}
public void dispense() { }
}
四:状态模式允许一个对象基于内部状态而拥有不同的行为。
和程序状态机不同,状态模式用类代表状态。
CONTEXT会将当前行为委托给当前状态对象。
通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
状态模式和测试模式拥有相同的雷同,但是他们意图不用。测试模式通常会用行为或算法来配置CONTEXT类。
状态模式允许CONTEXT随着状态的改变而改变行为。
状态转换可以由STATE类或CONTEXT类组成
使用状态模式通常会导致设计中类的数码大量增加
状态类可以被多个CONTEXT实例共享