状态模式
状态模式可以理解是策略者模式的特例,主要是用途上表现出特例
策略者模式链接: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了,不影响其他的状态
加入状态模式后,代价降低