Head First设计模式(阅读笔记)-12.状态模式

糖果机

假设有一个糖果机,每执行一个动作(曲线上的文字)会进入到不同的状态(圆圈中的文字),如下图所示:

在这里插入图片描述

根据上面的状态转换图,可以实现糖果机了:

public class GumballMachine{
    // 四个状态
    final static int SOLD_OUT = 0;  // 糖果售罄
    final static int NO_QUARTER = 1;  // 没有25分钱
    final static int HAS_QUARTER = 2;  // 有25分钱
    final static int SOLD = 3;  // 正在售出糖果
    
    int state = SOLD_OUT;  // 当前状态(一开始糖果机没有糖果)
    int count = 0;  // 机器中的糖果数
    
    public GumballMachine(int count){
        this.count = count;
        // 如果有库存,糖果机就开始进入到没有25分钱的状态(即开始等别人投钱)
        if(count > 0){  
            state = NO_QUARTER;  
        }
    }
    
    // 当有25分钱投入机器后
    public void insertQuarter(){
        // 当前状态为投了25分钱
        if(state == HAS_QUARTER){
            // 告诉顾客不能再投
        }
        // 当前状态为没投25分钱
        else if(state == NO_QUARTER){
            state = HAS_QUARTER;  // 修改状态为有25分钱
            // 告诉顾客现在成功投入25分钱
        }
        // 当前状态为糖果售罄
        else if(state == SOLD_OUT){
            // 告诉顾客现在没糖果卖了
        }
        // 当前状态为正在售出糖果
        else if(state == SOLD){
            // 告诉顾客正在出货
        }
    }
    
    // 当顾客尝试退回25分钱
    public void ejectQuarter(){
		...
    }
    
    // 当顾客尝试转动曲柄
    public void turnCrank(){
        ...
    }
    // 当机器开始弹出糖果
    public void dispense(){
        ...
    }
}

上述代码已经很完整了,但假设加入新功能,比如在曲柄转动时有一定机率弹出两个糖果,该如何实现?

在这里插入图片描述


状态模式

允许对象(糖果机)在内部状态改变时改变它的行为,对象看起啦好像修改了它的类


定义状态接口和类

在原代码中可以看出,每个状态都对应的相同的四个动作(insertQuarterejectQuarterturnCrankdispense),不如定义一个State接口,让每个状态都去实现该接口,以没有25分钱状态为例


public interface State{
    public void insertQuarter();
    public void ejectQuarter();
    public void turnCrank();
    public void dispense();
}
// 当前状态为没有25分钱
public class NoQuarterState implements State{
    GumballMachine gumballMachine;
    public NoQuarterState(GumballMachine gumballMachine){
        this.gumballMachine = gumballMachine;
    }
    public void insertQuarter(){
        // 打印机器接收了25分钱
        gumballMachine.setState(gumballMachine.getHasQuarterState());  // 修改机器状态
    }
    public void ejectQuarter(){
        // 打印都没给钱,不能要求退钱
    }
    public void turnCrank(){
        // 打印都没给钱,不能转动曲柄
    }
    public void dispense(){
        // 打印都没给钱,不能给糖果
    }
}
改造糖果机

不使用静态整数代表状态,改为使用State对象表示


public class GumballMachine{
    // 四个状态(可以继续加入赢家状态)
    State soldOutState;  // 糖果售罄
    State noQuarterState = 1;  // 没有25分钱
    State hasQuarterState = 2;  // 有25分钱
    State soldState = 3;  // 正在售出糖果
    
    State state = soldOutState;  // 当前状态(一开始糖果机没有糖果)
    int count = 0;  // 机器中的糖果数
    public GumballMachine(int count){
		soldOutState = new soldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
        if(count > 0){
            state = noQuarterState;
        }
    }
    
    // *下面行为委托当前的状态对象即可
    // 当有25分钱投入机器后
    public void insertQuarter(){
        state.insertQuarter();
    }
    
    // 当顾客尝试退回25分钱
    public void ejectQuarter(){
        state.ejectQuarter();
    }
    
    // 当顾客尝试转动曲柄
    public void turnCrank(){
        state.turnCrank();
        state.dispense();
    }
    // 用于释放糖果
	public void releaseBall(){
        if(count != 0){
            count = count - 1;
        }
    }
    // 对于四个状态和当前状态的getter方法,此处省略
}
展示糖果机

public class GumballMachineTest{
    public static void main(String[] args){
        GumballMachine gumballMachine = new GumballMachine(10);
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        ...
    }
}

已学模式


模式描述
状态模式封装基于状态的行为,将行为委托到当前状态
模板模式由子类决定如何实现算法中的某些步骤

参考

Head First 设计模式-状态模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值