一、定义
The State Pattern allows an object to alter its behavior
when its internal state changes. The object will appear to
change its class.
状态模式允许一个对象当它的内部状态改变时,改变它的行为。对象能够改变
它的类。
类图:
二、实例
实现口香糖自动贩卖机的状态变化:
翻译:No Quarter(默认状态),insert quarter(投入硬币),Has Quarter(已经投币状态),eject quarter(退回硬币),turns crank(拉动摇杆),Gumball Sold(即将出口香糖状态),dispense gumball(出口香糖), gumballs(口香糖数量),Out of Gumballs(口香糖售罄状态)
(一)直观思路,编写一个状态机类,实现全部操作:
enum GumballState {
NoQuarter,HasQuarter,GumballSold,OutOfGumballs
}
public class GumballMachine {
private final static int DEFAULT_SIZE=10;
private int gumballs;
private GumballState state;
public GumballMachine(int size) {
gumballs=size;
if(size<=0) {
state=GumballState.OutOfGumballs;
} else {
state=GumballState.NoQuarter;
}
}
public GumballMachine() {
this(DEFAULT_SIZE);
}
public void insertQuarter() {
if(state==GumballState.HasQuarter) {
System.out.println("You cannot insert another quarter, you can choose to eject or turn crack");
} else if(state==GumballState.GumballSold) {
System.out.println("You cannot insert another quarter, you can only dispense Gumball");
} else if(state==GumballState.OutOfGumballs) {
System.out.println("Sorry, the machine is sold out");
} else if(state==GumballState.NoQuarter) {
state=GumballState.HasQuarter;
System.out.println("You inserted a quarter!");
}
}
public void ejectQuarter() {
if(state==GumballState.GumballSold) {
System.out.println("It cannot eject your quarter, you can only choose to dispense Gumball");
} else if(state==GumballState.OutOfGumballs) {
System.out.println("Sorry, the machine is sold out");
} else if(state==GumballState.NoQuarter) {
System.out.println("You didn't put a quarter");
} else if(state==GumballState.HasQuarter) {
state=GumballState.NoQuarter;
System.out.println("The quarter will eject to you");
}
}
public void turnCrank() {
if(state==GumballState.GumballSold) {
System.out.println("You cannot turn crack again, you can only choose to dispense Gumball");
} else if(state==GumballState.OutOfGumballs) {
System.out.println("Sorry, the machine is sold out");
} else if(state==GumballState.NoQuarter) {
System.out.println("You have to insert a quarter first");
} else if(state==GumballState.HasQuarter) {
state=GumballState.GumballSold;
System.out.println("You turn crank");
}
}
public void dispenseGumball() {
if(state==GumballState.HasQuarter) {
System.out.println("You have to turn crack first");
} else if(state==GumballState.OutOfGumballs) {
System.out.println("Sorry, the machine is sold out");
} else if(state==GumballState.NoQuarter) {
System.out.println("You have to insert a quarter first");
} else if(state==GumballState.GumballSold) {
gumballs--;
System.out.println("The machine is to give you a gumball");
if(gumballs>0) {
state=GumballState.NoQuarter;
} else {
state=GumballState.OutOfGumballs;
}
}
}
@Override
public String toString() {
return "GumballMachine [gumballs=" + gumballs + ", state=" + state + "]\n";
}
}
测试类:
public class Test {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(5);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.dispenseGumball();
System.out.println(gumballMachine);
}
}
输出结果:
GumballMachine [gumballs=5, state=NoQuarter]
You inserted a quarter!
You turn crank
You cannot insert another quarter, you can only dispense Gumball
It cannot eject your quarter, you can only choose to dispense Gumball
You cannot turn crack again, you can only choose to dispense Gumball
The machine is to give you a gumball
GumballMachine [gumballs=4, state=NoQuarter]
You inserted a quarter!
The quarter will eject to you
You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=3, state=NoQuarter]
You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=2, state=NoQuarter]
You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=1, state=NoQuarter]
You inserted a quarter!
You turn crank
The machine is to give you a gumball
GumballMachine [gumballs=0, state=OutOfGumballs]
Sorry, the machine is sold out
Sorry, the machine is sold out
Sorry, the machine is sold out
GumballMachine [gumballs=0, state=OutOfGumballs]
分析:这样写纯粹是面向实现编程,当需求改变,必然违背开闭原则。
(二)新的需求,要求10%概率出两颗糖
public interface State {
void insertQuarter();
void ejectQuarter();
void turnCrank();
void dispenseGumball();
}
class GumballMachine {
private final static int DEFAULT_SIZE=10;
private int gumballs;
private State noQuarterState;
private State hasQuarterState;
private State soldOutState;
private State soldState;
private State winnerState;
private State state;
public GumballMachine(int size) {
noQuarterState=new NoQuarterState(this);
hasQuarterState=new HasQuarterState(this);
soldOutState=new SoldOutState(this);
soldState=new SoldState(this);
winnerState=new WinnerState(this);
gumballs=size;
if(size>0) {
state=noQuarterState;
} else {
state=soldOutState;
}
}
public GumballMachine() {
this(DEFAULT_SIZE);
}
public int getGumballs() {
return gumballs;
}
public void setGumballs(int gumballs) {
this.gumballs = gumballs;
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
state.dispenseGumball();
}
public void setState(State state) {
this.state=state;
}
public State getNoQuarterState() {
return noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public State getSoldOutState() {
return soldOutState;
}
public State getSoldState() {
return soldState;
}
public State getWinnerState() {
return winnerState;
}
public void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if(gumballs!=0) {
gumballs--;
}
}
@Override
public String toString() {
return "GumballMachine [gumballs=" + gumballs + ", state=" + state + "]\n";
}
}
class NoQuarterState implements State {
private GumballMachine machine;
public NoQuarterState(GumballMachine machine) {
this.machine=machine;
}
@Override
public void insertQuarter() {
System.out.println("You inserted a quarter");
machine.setState(machine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("You haven't insert a quarter");
}
@Override
public void turnCrank() {
System.out.println("You haven't insert a quarter");
}
@Override
public void dispenseGumball() {
System.out.println("You haven't insert a quarter");
}
}
class WinnerState implements State {
private GumballMachine machine;
public WinnerState(GumballMachine machine) {
this.machine=machine;
}
@Override
public void insertQuarter() {
System.out.println("You can’t insert another quarter");
}
@Override
public void ejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
@Override
public void turnCrank() {
System.out.println("You have turned crank already!");
}
@Override
public void dispenseGumball() {
System.out.println("Congratulations! You are a WINNER, and you can get two gumballs!");
machine.releaseBall();
if(machine.getGumballs()==0) {
System.out.println("Sold out!");
machine.setState(machine.getSoldOutState());
} else {
machine.releaseBall();
if(machine.getGumballs()==0) {
machine.setState(machine.getSoldOutState());
} else {
machine.setState(machine.getNoQuarterState());
}
}
}
}
class HasQuarterState implements State {
private Random random =new Random();
private GumballMachine machine;
public HasQuarterState(GumballMachine machine) {
this.machine=machine;
}
@Override
public void insertQuarter() {
System.out.println("You can’t insert another quarter");
}
@Override
public void ejectQuarter() {
System.out.println("Quarter returned!");
machine.setState(machine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("You turned...");
int ran=random.nextInt(10);
if(ran==0&&machine.getGumballs()>1) {
machine.setState(machine.getWinnerState());
} else {
machine.setState(machine.getSoldState());
}
}
@Override
public void dispenseGumball() {
System.out.println("No gumball dispensed");
}
}
class SoldOutState implements State {
private GumballMachine machine;
public SoldOutState(GumballMachine machine) {
this.machine=machine;
}
@Override
public void insertQuarter() {
System.out.println("The machine is sold out!");
}
@Override
public void ejectQuarter() {
System.out.println("The machine is sold out!");
}
@Override
public void turnCrank() {
System.out.println("The machine is sold out!");
}
@Override
public void dispenseGumball() {
System.out.println("The machine is sold out!");
}
}
class SoldState implements State {
private GumballMachine machine;
public SoldState(GumballMachine machine) {
this.machine=machine;
}
@Override
public void insertQuarter() {
System.out.println("You can’t insert another quarter");
}
@Override
public void ejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
@Override
public void turnCrank() {
System.out.println("You have turned crank already!");
}
@Override
public void dispenseGumball() {
machine.releaseBall();
if(machine.getGumballs()==0) {
System.out.println("Sold out!");
machine.setState(machine.getSoldOutState());
} else {
machine.setState(machine.getNoQuarterState());
}
}
}
测试类:
public class Test {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(10);
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
System.out.println(gumballMachine);
for(int i=0;i<10;i++) {
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}
}
输出结果:
You inserted a quarter
Quarter returned!
GumballMachine [gumballs=10, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
Congratulations! You are a WINNER, and you can get two gumballs!
A gumball comes rolling out the slot...
A gumball comes rolling out the slot...
GumballMachine [gumballs=8, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=7, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=6, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=5, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=4, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=3, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=2, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
GumballMachine [gumballs=1, state=chapter10.state.demo2.NoQuarterState@6d06d69c]
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Sold out!
GumballMachine [gumballs=0, state=chapter10.state.demo2.SoldOutState@7852e922]
The machine is sold out!
The machine is sold out!
The machine is sold out!
GumballMachine [gumballs=0, state=chapter10.state.demo2.SoldOutState@7852e922]
类图:
三、总结
状态模式很容易理解,它主要用来解决状态转换的问题,如进程的五种状态的转换,自动贩卖机的状态转换。UML中也有状态图,也可以用状态模式来解决。