状态模式入门

状态模式

状态模式可以理解是策略者模式的特例,主要是用途上表现出特例

策略者模式链接:https://blog.csdn.net/dengjili/article/details/79273928

简单例子理解

饮料自动贩卖机

这里写图片描述

自动贩卖机状态图

简化为以下几种状态
这里写图片描述

对应代码

package headfirst.hd.state.eg;

public class Machine {

    enum State {
        SOLD_OUT, NO_MONEY, HAS_MONEY, SOLD
    }

    // 初始化机器
    State state = State.SOLD_OUT;
    int count = 0;

    public Machine(State state, int count) {
        this.state = state;
        this.count = count;
    }

    // 投币
    public void insertMoney() {
        if (state.equals(State.SOLD_OUT)) {
            System.out.println("机器已经卖完了,别投币!!!");
        } else if (state.equals(State.NO_MONEY)) {
            state = State.HAS_MONEY;
            System.out.println("投币成功!!!");
        } else if (state.equals(State.HAS_MONEY)) {
            System.out.println("已经投币,请选择饮料!!!");
        } else if (state.equals(State.SOLD)) {
            System.out.println("请稍等,正在出货!!!");
        }
    }

    // 退钱
    public void ejectMoney() {
        if (state.equals(State.SOLD_OUT)) {
            System.out.println("机器已经卖完了,无法投钱,退钱!!!");
        } else if (state.equals(State.NO_MONEY)) {
            System.out.println("未投币,不能退钱!!!");
        } else if (state.equals(State.HAS_MONEY)) {
            state = State.NO_MONEY;
            System.out.println("退币成功!!!");
        } else if (state.equals(State.SOLD)) {
            System.out.println("正在出货,不能退钱!!!");
        }
    }

    // 选择饮料确认
    public void comfirm() {
        if (state.equals(State.SOLD_OUT)) {
            System.out.println("机器已经卖完了,选择饮料!!!");
        } else if (state.equals(State.NO_MONEY)) {
            System.out.println("请先投币!!!");
        } else if (state.equals(State.HAS_MONEY)) {
            System.out.println("选择成功!!!");
            state = State.SOLD;
            out();
        } else if (state.equals(State.SOLD)) {
            System.out.println("已经选择了,正在出货中!!!");
        }
    }

    // 出货
    public void out() {
        if (state.equals(State.SOLD_OUT)) {
            System.out.println("机器已经卖完了,无法出货!!!");
        } else if (state.equals(State.NO_MONEY)) {
            System.out.println("未投币,无法出货!!!");
        } else if (state.equals(State.HAS_MONEY)) {
            System.out.println("请先选择饮料!!!");
        } else if (state.equals(State.SOLD)) {
            System.out.println("出货!!!");

            count = count - 1;
            if (count == 0) {
                state = State.SOLD_OUT;
                System.out.println("已卖完!!!");
            } else {
                state = State.NO_MONEY;
            }
        }
    }

    @Override
    public String toString() {
        return "Machine [state=" + state + ", count=" + count + "]";
    }


}

测试类

package headfirst.hd.state.eg;

import headfirst.hd.state.eg.Machine.State;

public class TestMachine {

    public static void main(String[] args) {
        Machine machine = new Machine(State.NO_MONEY, 5);
        System.out.println(machine);

        //正常购买
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);
        //购买,然后退钱
        machine.insertMoney();
        machine.ejectMoney();
        machine.comfirm();
        System.out.println(machine);

        //正常购买
        machine.insertMoney();
        machine.comfirm();
        machine.insertMoney();
        machine.comfirm();
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);

        //机器已经卖完后操作
        machine.insertMoney();
        machine.ejectMoney();
        machine.comfirm();
    }

}

测试结果

Machine [state=NO_MONEY, count=5]
投币成功!!!
选择成功!!!
出货!!!
Machine [state=NO_MONEY, count=4]
投币成功!!!
退币成功!!!
请先投币!!!
Machine [state=NO_MONEY, count=4]
投币成功!!!
选择成功!!!
出货!!!
投币成功!!!
选择成功!!!
出货!!!
投币成功!!!
选择成功!!!
出货!!!
Machine [state=NO_MONEY, count=1]
投币成功!!!
选择成功!!!
出货!!!
已卖完!!!
Machine [state=SOLD_OUT, count=0]
机器已经卖完了,别投币!!!
机器已经卖完了,无法投钱,退钱!!!
机器已经卖完了,选择饮料!!!

引入新状态引发的问题

第二代机器引入中奖状态
这里写图片描述

对应代码

public class Machine {

    enum State {
        SOLD_OUT, NO_MONEY, HAS_MONEY, SOLD, WINNING
    }

    // 初始化机器
    State state = State.SOLD_OUT;
    int count = 0;

    public Machine(State state, int count) {
        this.state = state;
        this.count = count;
    }

    // 投币
    public void insertMoney() {
        if (state.equals(State.SOLD_OUT)) {

        } else if (state.equals(State.NO_MONEY)) {

        } else if (state.equals(State.HAS_MONEY)) {

        } else if (state.equals(State.SOLD)) {

        } else if (state.equals(State.WINNING)) {

        }
    }
}

其中,还有其他方法都需要加上if分支

    // 退钱
    public void ejectMoney()

    // 选择饮料确认
    public void comfirm()

    // 等等

以上操作违法了封闭原则,修改了大量已存在的代码

引入状态模式

这里写图片描述

对应代码

状态接口

package headfirst.hd.state.eg2;

public interface State {
    void insertMoney();
    void ejectMoney();
    void comfirm();
    void out();
}

对应状态

package headfirst.hd.state.eg2;

public class SoldOutState implements State {

    Machine machine;

    public SoldOutState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        System.out.println("机器已经卖完了,别投币!!!");
    }

    @Override
    public void ejectMoney() {
        System.out.println("机器已经卖完了,无法投钱,退钱!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("机器已经卖完了,选择饮料!!!");
    }

    @Override
    public void out() {
        System.out.println("机器已经卖完了,无法出货!!!");
    }

}
package headfirst.hd.state.eg2;

public class NoMoneyState implements State {

    Machine machine;

    public NoMoneyState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        machine.hasMoneyState();
        System.out.println("投币成功!!!");
    }

    @Override
    public void ejectMoney() {
        System.out.println("未投币,不能退钱!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("请先投币!!!");
    }

    @Override
    public void out() {
        System.out.println("未投币,无法出货!!!");
    }

}
package headfirst.hd.state.eg2;

public class HasMoneyState implements State {

    Machine machine;

    public HasMoneyState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        System.out.println("已经投币,请选择饮料!!!");
    }

    @Override
    public void ejectMoney() {
        machine.noMoneyState();
        System.out.println("退币成功!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("选择成功!!!");
        machine.soldState();
    }

    @Override
    public void out() {
        System.out.println("请先选择饮料!!!");
    }

}
package headfirst.hd.state.eg2;

public class SoldState implements State {

    Machine machine;

    public SoldState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        System.out.println("请稍等,正在出货!!!");
    }

    @Override
    public void ejectMoney() {
        System.out.println("正在出货,不能退钱!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("已经选择了,正在出货中!!!");
    }

    @Override
    public void out() {
        System.out.println("出货!!!");

        machine.setCount(machine.getCount() - 1);
        if (machine.getCount() == 0) {
            machine.soldOutState();
            System.out.println("已卖完!!!");
        } else {
            machine.noMoneyState();
        }
    }

}

核心控制器

package headfirst.hd.state.eg2;

public class Machine {

    private State soldOutState = new SoldOutState(this);
    private State noMoneyState = new NoMoneyState(this);
    private State hasMoneyState = new HasMoneyState(this);
    private State soldState = new SoldState(this);

    // 初始化机器
    private int count = 0;
    private State state = null;

    public Machine(int count) {
        this.count = count;

        if (this.count > 0) {
            noMoneyState();
        } else {
            soldOutState();
        }
    }

    public void soldOutState() {
        state = soldOutState;
    }

    public void noMoneyState() {
        state = noMoneyState;
    }

    public void hasMoneyState() {
        state = hasMoneyState;
    }

    public void soldState() {
        state = soldState;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public int getCount() {
        return count;
    }

    // 投币
    public void insertMoney() {
        state.insertMoney();
    }

    // 退钱
    public void ejectMoney() {
        state.ejectMoney();
    }

    // 选择饮料确认
    public void comfirm() {
        state.comfirm();
        out();
    }

    // 出货
    public void out() {
        state.out();
    }

    @Override
    public String toString() {
        return "Machine [state=" + state.getClass() + ", count=" + count + "]";
    }


}

测试

package headfirst.hd.state.eg2;

public class TestMachine {

    public static void main(String[] args) {
        Machine machine = new Machine(5);
        System.out.println(machine);

        //正常购买
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);
        //购买,然后退钱
        machine.insertMoney();
        machine.ejectMoney();
        machine.comfirm();
        System.out.println(machine);

        //正常购买
        machine.insertMoney();
        machine.comfirm();
        machine.insertMoney();
        machine.comfirm();
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);
        machine.insertMoney();
        machine.comfirm();
        System.out.println(machine);

        //机器已经卖完后操作
        machine.insertMoney();
        machine.ejectMoney();
        machine.comfirm();
    }

}

测试结果

Machine [state=class headfirst.hd.state.eg2.NoMoneyState, count=5]
投币成功!!!
选择成功!!!
出货!!!
Machine [state=class headfirst.hd.state.eg2.NoMoneyState, count=4]
投币成功!!!
退币成功!!!
请先投币!!!
未投币,无法出货!!!
Machine [state=class headfirst.hd.state.eg2.NoMoneyState, count=4]
投币成功!!!
选择成功!!!
出货!!!
投币成功!!!
选择成功!!!
出货!!!
投币成功!!!
选择成功!!!
出货!!!
Machine [state=class headfirst.hd.state.eg2.NoMoneyState, count=1]
投币成功!!!
选择成功!!!
出货!!!
已卖完!!!
Machine [state=class headfirst.hd.state.eg2.SoldOutState, count=0]
机器已经卖完了,别投币!!!
机器已经卖完了,无法投钱,退钱!!!
机器已经卖完了,选择饮料!!!
机器已经卖完了,无法出货!!!

和之前一致

加入新状态

这里写图片描述

实现新状态

package headfirst.hd.state.eg2;

public class WinningState implements State {

    Machine machine;

    public WinningState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        System.out.println("请稍等,正在出货!!!");
    }

    @Override
    public void ejectMoney() {
        System.out.println("正在出货,不能退钱!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("已经选择了,正在出货中!!!");
    }

    @Override
    public void out() {
        System.out.println("中奖!!!");
        System.out.println("中奖,返回购买金额,出货!!!");
        System.out.println("中奖!!!");

        machine.setCount(machine.getCount() - 1);
        if (machine.getCount() == 0) {
            machine.soldOutState();
            System.out.println("已卖完!!!");
        } else {
            machine.noMoneyState();
        }
    }

}

更改状态的上一级状态

package headfirst.hd.state.eg2;

import java.util.Random;

public class HasMoneyState implements State {

    Machine machine;

    public HasMoneyState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertMoney() {
        System.out.println("已经投币,请选择饮料!!!");
    }

    @Override
    public void ejectMoney() {
        machine.noMoneyState();
        System.out.println("计算退余额!!!");
    }

    @Override
    public void comfirm() {
        System.out.println("选择成功!!!");

        int nextInt = new Random().nextInt(10);
        if (nextInt % 6 == 0) {
            machine.winningState();
        } else {
            machine.soldState();
        }
    }

    @Override
    public void out() {
        System.out.println("请先选择饮料!!!");
    }

}

修改ok了,不影响其他的状态

加入状态模式后,代价降低

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值