深入浅出设计模式-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实例共享