-
定义
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States)。 -
类图
State -
例子
//没有硬币状态
public class NoQuarterState implements State{
GumballMachine gumballMachine;
//通过构造器得到糖果机的引用,然后将它记录在实例变量中
public NoQuarterState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
//有人投币,改变机器状态到HasQuarterState
public void insertQuater(){
System.out.println("You insert a quater");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
//没给钱,不能要求退钱
public void ejectQuarter(){
System.out.println("You haven't inserted a quarter");
}
//没给钱,不能转手柄,要糖果
public void turnCrank(){
System.out.println("You turned,but there's no quarter");
}
//没给钱,不能发糖果
public void dispense(){
System.out.println("You need to pay first");
}
}
//有硬币状态
public class HasQuarterState implements State{
//增加一个随机数产生器,产生10%赢得机会
Random randomWinner= new Random(System.currentTimeMillis());
GumballMachine gumballMachine;
//状态被实例化是,传入GumballMachine的引用作为参数
public HasQuarterState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
//不能连续投币两次
public void insertQuater(){
System.out.println("You can't insert another quater");
}
//退钱,并将状态转到NoQuarterState
public void ejectQuarter(){
System.out.println("Quarter returned");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
//状态转到SoldState
public void turnCrank(){
System.out.println("You turned...");
int winner=randomWinner.nextInt(10);
if((winner==0)&&(gumballMachine.getCount()>1)){
gumballMachine.setState(gumballMachine.getWinnerState());
}else{
gumballMachine.setState(gumballMachine.getSoldState());
}
}
public void dispense(){
System.out.println("No gumball dispensed");
}
}
public class SoldState implements State{
GumballMachine gumballMachine;
//状态被实例化是,传入GumballMachine的引用作为参数
public SoldState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
//以下的动作都不合法
public void insertQuater(){
System.out.println("Please wait,we're already giving you a gumball");
}
public void ejectQuarter(){
System.out.println("Sorry,you already turned the crank");
}
public void turnCrank(){
System.out.println("Turning twice doesn't get you another gumball");
}
//发糖
public void dispense(){
gumballMachine.releaseBall();
if(gumballMachine.getCount()>0){
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
System.out.println("Oops,out of gumball");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
public class WinnerState implements State{
GumballMachine gumballMachine;
//状态被实例化是,传入GumballMachine的引用作为参数
public WinnerState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
//以下的动作都不合法
public void insertQuater(){
System.out.println("Please wait,we're already giving you a gumball");
}
public void ejectQuarter(){
System.out.println("Sorry,you already turned the crank");
}
public void turnCrank(){
System.out.println("Turning twice doesn't get you another gumball");
}
//发糖
public void dispense(){
System.out.println("YOU'RE A WINNER! You get two gumballs for your quater")
gumballMachine.releaseBall();
if(gumballMachine.getCount()==0){
gumballMachine.setState(gumballMachine.SoldOutState());
}else{
gumballMachine.releaseBall();
if(gumballMachine.getCount()>0){
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
System.out.println("Oops,out of gumball");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
}
//糖果售罄状态
public class SoldOutState implements State{
GumballMachine gumballMachine;
//状态被实例化是,传入GumballMachine的引用作为参数
public SoldOutState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
//在糖果售罄的状态下,除非重新填充糖果机,否则不做任何事
public void insertQuater(){
System.out.println("You can't insert a quarter,the machine is sold out");
}
public void ejectQuarter(){
System.out.println("You can't eject,you haven't inserted a quarter yet");
}
public void turnCrank(){
System.out.println("You turned,but there are no gumballs");
}
public void dispense(){
System.out.println("No gumball dispensed");
}
}
public class GumballMachine{
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State winnerState;
State state = soldOutState;
int count=0; //记录机器内装有多少糖果,开始机器是没有糖果的
//构造器取得糖果的初始数目并把它存放在一个实例变量中
public GumballMachine(int numberGumballs){
soldOutState=new SoldOutState(this);
noQuarterState=new NoQuarterState(this);
hasQuarterState=new HasQuarterState(this);
soldState=new SoldState(this);
winnerState=new WinnerState(this);
this.count=numberGumballs;
//若糖果数>0,则将状态设为noQuarterState
if(numberGumballs>0){
state=noQuarterState;
}
}
//设置动作,并因动作改变相应的状态
public void insertQuarter(){
state.insertQuarter();
}
public void ejectQuarter(){
state.ejectQuarter();
}
/*不需要在GumballMachine中准备一个dispense()的动作方法,因为这是一个内部动作;
用户不可以直接要求一个机器发放糖果。但可以在状态对象的turnCrank()方法中调用dispense()方法*/
public void turnCrank(){
state.turnCrank();
state.dispense();
}
//允许其他对象将机器的状态转换到不同的状态
void setState(State state){
this.state=state;
}
//提供一个releaseBall()的辅助方法来释放糖果,并将count值减1
void releaseBall(){
System.out.println("A gumball comes rolling out the slot...");
if(count!=0){
count=count-1;
}
}
//更新糖果机内的糖果数目,并重置机器的状态
void refill(int count){
this.count=count;
state=noQuarterState;
}
/*其他方法,包括像getNoQuarterState()这样的用来获得每个对象的方法,
还包括可以取得糖果数目的getCount()方法*/
}
//演示
public class GumballMachineTestDriver{
public static void main(String[] args){
GumballMachine gumballMachine= new GumballMachine(5);//糖果机装5颗糖
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println(gumballMachine);
}
}
代码来源于《Head First 设计模式》
补充
- 后面会发现,状态模式 的类图和 策略模式 竟然是一样的,没有错,就是一样的,但是目的不一样,状态模式强调 一个「流程」,而策略模式则强调 解决「方案」,换句话说就是,用多个子类和用一个子类。
- 状态模式在处理长流程的逻辑时非常有用。
网友评论