HeadFirst 设计模式 10状态模式(糖果机)

来源:互联网 发布:投影机网络控制软件 编辑:程序博客网 时间:2024/05/17 23:55

状态模式

允许对象在内部状态改变是改变它的行为,对象看起来好像修改了它的类。

第一句指:该模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,且行为会随着内部状态而改变。

“看起来好像修改了它的类”指从客户的角度看:若你说使用的对象能够完全改变他的行为,那么你会觉得,这个对象实际上是从别的类实例化而来的。然后实际上,是在使用组合通过简单引用不同的状态对象来造成改变的假象。

糖果机实例

 



//没有硬币状态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);  }}



区分模式

状态模式:封装基于状态的行为,并将行为委托到当前状态

策略模式:将可以互换的行为封装起来。然后使用委托的方法,觉得使用哪一个行为

模板方法模式:由子类决定如何实现算法中的某些步骤


要点

(1)状态模式允许一个对象基于内部状态而拥有不同的行为。

(2)和程序状态机(PSM)不同,状态模式用类来表示状态。

(3)Context会将行为委托给当前状态对象。

(4)通过将每一个状态封装进一个类,我们把以后需要做的任何改变局部化了。

(5)状态模式和策略模式有相同的类图,但是他们的意图不同。

(6)策略模式通常会用行为或算法配置Context类。

(7)状态模式允许Context随着状态的改变而改变行为。

(8)状态转换可以有State类或Context类控制。

(9)使用状态模式通常会导致设计中类的数目大量增加。

(10)状态栏可以被多个Context实例共享。

0 0
原创粉丝点击