状态模式允许在内部状态时改变它的行为,在外部看起来好像修改了类。状态模式可以延伸出状态机的概念,状态机据我自己所知在电商系统中用来控制订单状态的流转。关于状态机,大家可以在评论中可以补充一下(状态机的更多应用场景)。
类图
- State:该类通常是一个接口或者抽象类,具体视情况而定
- ConcreteState:具体的状态类,实现状态的控制
- Context:具体需要使用状态的客户段,在其内部通常有各个状态的引用以及一个当前状态的引用,当调用handle方法时,其实将方法的调用转发给给当前状态的handle方法去执行
场景模拟
下面我们模拟一个糖果机的场景,在该场景中我们简化了部分逻辑,毕竟我们只是为了了解学习状态模式,而不是实现一个真正的糖果机系统。下面我们分析一下糖果机的场景。首先我们需要一台糖果机,其次该机器有以下集中状态,待投币状态,已投币状态,售出糖果状态,售空状态。下面我们开始我们的状态分析,首先我们需要一个State接口。
State接口
该接口主要有以下方法,投币、退币、摇动手柄、售出糖果,上面这四个方法会改变糖果机的状态。
public interface State {
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispense();
}
NoQuarterState类(待投币状态)
在糖果机在待投币状态下,我们唯一能对糖果机做的操作就是投入硬币,当投入硬币之后我们的糖果机就变成了已投币状态。
public class NoQuarterState implements State {
private GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You insert a quarter!");
gumballMachine.setCurrentState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void turnCrank() {
throw new UnsupportedOperationException();
}
@Override
public void dispense() {
throw new UnsupportedOperationException();
}
}
HasQuarterState类(已投币状态)
在糖果机有币的状态下我们可以做两种操作,一种选择退出硬币(待投币状态),还有一种就是摇动摇杆去获得糖果(售出糖果状态)。
public class HasQuarterState implements State {
private GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void ejectQuarter() {
System.out.println("You eject a quarter!");
gumballMachine.setCurrentState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("You turn this crank!");
gumballMachine.setCurrentState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
throw new UnsupportedOperationException();
}
}
SoldState(售出糖果状态)
在该状态下,我们需要将糖果给用户,因此我们调用糖果机的售出糖果方法,此时我们需要判断糖果机里是否还有糖果,如果没有糖果了我们就将糖果机置为售空状态(等待工作人员补充糖果后糖果机才可以被再次使用),如果还有糖果我们就将糖果机置为待投币状态,等待下一个用户。
public class SoldState implements State {
private GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void ejectQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void turnCrank() {
throw new UnsupportedOperationException();
}
@Override
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setCurrentState(gumballMachine.getNoQuarterState());
} else {
gumballMachine.setCurrentState(gumballMachine.getSoldOutState());
}
}
}
SoldOutState(售空状态)
在售空状态下我们无法做任何操作。
public class SoldOutState implements State {
private GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void ejectQuarter() {
throw new UnsupportedOperationException();
}
@Override
public void turnCrank() {
throw new UnsupportedOperationException();
}
@Override
public void dispense() {
throw new UnsupportedOperationException();
}
}
GumballMachine(糖果机)
有了状态的控制,我们当然要有台糖果机。在糖果机中,我们有四个状态和糖果机当前状态的引用,你会发现我们只是将请求委托给了糖果机的当前状态去实现。
public class GumballMachine {
private NoQuarterState noQuarterState;
private HasQuarterState hasQuarterState;
private SoldState soldState;
private SoldOutState soldOutState;
private State currentState;
private int count;
public GumballMachine(int count) {
this.noQuarterState = new NoQuarterState(this);
this.hasQuarterState = new HasQuarterState(this);
this.soldState = new SoldState(this);
this.soldOutState = new SoldOutState(this);
this.count = count;
currentState = noQuarterState;
}
public GumballMachine(State currentState) {
this.currentState = currentState;
}
public void setCurrentState(State currentState) {
this.currentState = currentState;
}
public void insertQuarter() {
currentState.insertQuarter();
}
public void ejectQuarter() {
currentState.ejectQuarter();
}
public void turnCrank() {
currentState.turnCrank();
dispense();
}
public void dispense() {
currentState.dispense();
}
public void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count -= 1;
}
}
public NoQuarterState getNoQuarterState() {
return noQuarterState;
}
public HasQuarterState getHasQuarterState() {
return hasQuarterState;
}
public SoldState getSoldState() {
return soldState;
}
public SoldOutState getSoldOutState() {
return soldOutState;
}
public int getCount() {
return count;
}
}
测试糖果机
一切准备就绪,是时候测试我们的糖果机了。至于下面的结果大家自己去跑测试吧。
public class GumballMachineTest {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(2);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("------------------------------");
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("------------------------------");
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("------------------------------");
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。