状态(state)模式以及和策略(strategy)的比较

来源:互联网 发布:淘宝卖家处理退货申请 编辑:程序博客网 时间:2024/06/06 01:20

一.概念

    状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式。

  状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

   状态模式的结构

  用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式的示意性类图如下所示:

  状态模式所涉及到的角色有:

  ●  环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。

  ●  抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。

  ●  具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

  源代码

  环境角色类

复制代码
public class Context {    //持有一个State类型的对象实例    private State state;    public void setState(State state) {        this.state = state;    }    /**     * 用户感兴趣的接口方法     */    public void request(String sampleParameter) {        //转调state来处理        state.handle(sampleParameter);    }}
复制代码

  抽象状态类

复制代码
public interface State {    /**     * 状态对应的处理     */    public void handle(String sampleParameter);}
复制代码

  具体状态类

复制代码
public class ConcreteStateA implements State {    @Override    public void handle(String sampleParameter) {                System.out.println("ConcreteStateA handle :" + sampleParameter);    }}
复制代码
复制代码
public class ConcreteStateB implements State {    @Override    public void handle(String sampleParameter) {                System.out.println("ConcreteStateB handle :" + sampleParameter);    }}
复制代码

  客户端类

复制代码
public class Client {    public static void main(String[] args){        //创建状态        State state = new ConcreteStateB();        //创建环境        Context context = new Context();        //将状态设置到环境中        context.setState(state);        //请求        context.request("test");    }}
复制代码

  从上面可以看出,环境类Context的行为request()是委派给某一个具体状态类的。通过使用多态性原则,可以动态改变环境类Context的属性State的内容,使其从指向一个具体状态类变换到指向另一个具体状态类,从而使环境类的行为request()由不同的具体状态类来执行。

二、head first中的例子

糖果机共有5个状态:没有25分钱、有25分钱、售出糖果、糖果售罄、赢家状态,这里从下面的UML状态图可以看到,Visio里使用椭圆形表示状态,还有引发糖果机状态发生转换的事件动作。

我使用Visio2003绘制的糖果机状态图,画得不太好,可能不是很标准,UML对于面向对象的软件设计很重要。

 

对应的Java代码如下:

[java] view plaincopy
  1. //State.java  
  2. package State;  
  3. /* 
  4.  * 状态接口State 
  5.  */  
  6. public interface State {  
  7.    public void insertQuarter();   // 投入25分钱  
  8.    public void ejectQuarter();    // 拒绝25分钱  
  9.    public void turnCrank();       // 转动曲柄  
  10.    public void dispense();        // 发放糖果  
  11. }  
  12.   
  13.   
  14. //NoQuarterState.java  
  15. package State;  
  16. import State.GumballMachine;  
  17. /* 
  18.  * 没有25分钱状态,实现了State接口 
  19.  */  
  20.   
  21. public class NoQuarterState implements State{  
  22.     GumballMachine gumballMachine;  
  23.       
  24.     public NoQuarterState(GumballMachine gumballMachine){  
  25.         this.gumballMachine=gumballMachine;  
  26.     }  
  27.     // 投入25分钱  
  28.     public void insertQuarter() {  
  29.         System.out.println("You insert a quarter");  
  30.         gumballMachine.setState(gumballMachine.getHasQuarterState());  
  31.     }  
  32.     // 拒绝25分钱  
  33.     public void ejectQuarter() {  
  34.         System.out.println("You haven't insert a quarter");  
  35.     }  
  36.     // 转动曲柄  
  37.     public void turnCrank() {  
  38.         System.out.println("You turned crank,but you there's no quarter");  
  39.     }  
  40.     // 发放糖果  
  41.     public void dispense() {  
  42.         System.out.println("You need to pay first");  
  43.     }  
  44. }  
  45.   
  46.   
  47. //HasQuarterState.java  
  48. package State;  
  49. import java.util.Random;  
  50.   
  51. import State.GumballMachine;  
  52. /* 
  53.  * 有25分钱状态,实现了State接口 
  54.  */  
  55. public class HasQuarterState implements State {  
  56.     Random randomWinner = new Random(System.currentTimeMillis()); //首先我们增加一个随机数产生器,产生10%赢的机  
  57.   
  58. 会  
  59.     GumballMachine gumballMachine;  
  60.       
  61.     public HasQuarterState(GumballMachine gumballMachine){  
  62.         this.gumballMachine = gumballMachine;  
  63.     }  
  64.     // 投入25分钱  
  65.     public void insertQuarter() {  
  66.         System.out.println("You can not insert anther quarter");  
  67.     }  
  68.     // 拒绝25分钱  
  69.     public void ejectQuarter() {  
  70.         System.out.println("Quarter returned");  
  71.         gumballMachine.setState(gumballMachine.getNoQuarterState());  
  72.     }  
  73.     // 转动曲柄  
  74.     public void turnCrank() {  
  75.         System.out.println("You turned...");  
  76.         int winner = randomWinner.nextInt(10);  
  77.         System.out.println("winner =" + winner);  
  78.         if((winner ==0) && (gumballMachine.getCount() > 1)) {  
  79.             gumballMachine.setState(gumballMachine.getWinnerState());  
  80.         } else {  
  81.             gumballMachine.setState(gumballMachine.getSoldState());  
  82.         }  
  83.     }  
  84.     // 发放糖果  
  85.     public void dispense() {  
  86.         System.out.println("No gumball dispensed");  
  87.     }  
  88. }  
  89.   
  90. //SoldState.java  
  91. package State;  
  92. import State.GumballMachine;  
  93. /* 
  94.  * 售出糖果状态,实现了State接口 
  95.  */  
  96. public class SoldState implements State{  
  97.       
  98.     GumballMachine gumballMachine;  
  99.     public SoldState(GumballMachine gumballMachine) {  
  100.         this.gumballMachine = gumballMachine;  
  101.     }  
  102.     // 投入25分钱  
  103.     public void insertQuarter() {  
  104.         System.out.println("Please wait, we're already giving you a gumball");  
  105.     }  
  106.     // 拒绝25分钱  
  107.     public void ejectQuarter() {  
  108.         System.out.println("Sorry,you have already turn crank");  
  109.     }  
  110.     // 转动曲柄  
  111.     public void turnCrank() {  
  112.         System.out.println("trun twice ,doesn't give you anthor gamball!");  
  113.     }  
  114.     // 发放糖果  
  115.     public void dispense() {  
  116.         gumballMachine.releaseBall();  
  117.             if(gumballMachine.getCount()>0){  
  118.                 gumballMachine.setState(gumballMachine.getNoQuarterState());  
  119.             } else {  
  120.             System.out.println("Opps,out of gamball!");   
  121.             gumballMachine.setState(gumballMachine.getSoldOutState());  
  122.         }  
  123.     }  
  124. }  
  125.   
  126.   
  127. //SoldOutState.java  
  128. package State;  
  129. import State.GumballMachine;  
  130. /* 
  131.  * 通过售罄状态,实现了State接口 
  132.  */  
  133. public class SoldOutState implements State{  
  134.       
  135.     GumballMachine gumballMachine;  
  136.     public SoldOutState(GumballMachine gumballMachine){  
  137.         this.gumballMachine=gumballMachine;  
  138.     }  
  139.     // 投入25分钱  
  140.     public void insertQuarter() {  
  141.         System.out.println("You can't insert a quarter, the machine is sold out");  
  142.     }  
  143.     // 拒绝25分钱  
  144.     public void ejectQuarter() {  
  145.         // TODO Auto-generated method stub  
  146.         System.out.println("You can't eject, you haven't inserted a quarter yet");  
  147.     }  
  148.     // 转动曲柄  
  149.     public void turnCrank() {  
  150.         // TODO Auto-generated method stub  
  151.         System.out.println("You turned, but there are no gumballs");  
  152.     }  
  153.     // 发放糖果  
  154.     public void dispense() {  
  155.         // TODO Auto-generated method stub  
  156.         System.out.println("No gumball dispensed");  
  157.     }  
  158. }  
  159.   
  160.   
  161. //WinnerState.java  
  162. package State;  
  163. import State.GumballMachine;  
  164. /* 
  165.  * 赢家状态,实现了State接口 
  166.  */  
  167. public class WinnerState implements State{  
  168.     GumballMachine gumballMachine;  
  169.       
  170.     public WinnerState(GumballMachine gumballMachine){  
  171.         this.gumballMachine = gumballMachine;  
  172.     }  
  173.     // 投入25分钱  
  174.     @Override  
  175.     public void insertQuarter() {  
  176.         // TODO Auto-generated method stub  
  177.         System.out.println("Please wait, we're already giving you a gumball");  
  178.     }  
  179.     // 拒绝25分钱  
  180.     @Override  
  181.     public void ejectQuarter() {  
  182.         // TODO Auto-generated method stub  
  183.         System.out.println("Sorry,you have already turn crank");  
  184.     }  
  185.     // 转动曲柄  
  186.     @Override  
  187.     public void turnCrank() {  
  188.         // TODO Auto-generated method stub  
  189.         System.out.println("trun twice ,doesn't give you anthor gamball!");  
  190.     }  
  191.     // 发放糖果  
  192.     @Override  
  193.     public void dispense() {  
  194.         // TODO Auto-generated method stub  
  195.         System.out.println("You're a Winner! You get two gumballs for your quarter");  
  196.         gumballMachine.releaseBall();  
  197.         if(gumballMachine.getCount() == 0) {  
  198.             gumballMachine.setState(gumballMachine.getSoldOutState());  
  199.         } else {  
  200.             gumballMachine.releaseBall();  
  201.             if(gumballMachine.getCount()>0){  
  202.                 gumballMachine.setState(gumballMachine.getNoQuarterState());  
  203.             } else {  
  204.                 System.out.println("Opps,out of gamball!");   
  205.                gumballMachine.setState(gumballMachine.getSoldOutState());  
  206.            }  
  207.         }  
  208.     }  
  209. }  
  210.   
  211.   
  212. //糖果机上下文环境类Java源文件 GumballMachine.java  
  213. package State;  
  214. import State.HasQuarterState;  
  215. import State.NoQuarterState;  
  216. import State.SoldOutState;  
  217. import State.SoldState;  
  218. import State.WinnerState;  
  219. import State.State;  
  220. /* 
  221.  *  糖果机器上下文环境接口类 GumballMachine 
  222.  */  
  223.   
  224. public class GumballMachine {  
  225.     //状态实例  
  226.     State soldOutState;  
  227.     State noQuarterState;  
  228.     State hasQuarterState;  
  229.     State soldState;  
  230.     State winnerState;  
  231.       
  232.     // 实例变量state,初始化为糖果售罄状态  
  233.     State state = soldOutState;   
  234.     // 记录机器内装有糖果的数目,开始机器是没有装糖果的  
  235.     int count=0;  
  236.     // 构造器取得糖果的初始数目并把它放在一个实例变量count中  
  237.     public GumballMachine(int numberGumballs) {  
  238.         // 每种状态都创建一个状态实例  
  239.         soldOutState=new SoldOutState(this);  
  240.         noQuarterState=new NoQuarterState(this);  
  241.         hasQuarterState=new HasQuarterState(this);  
  242.         soldState=new SoldState(this);  
  243.         winnerState = new WinnerState(this);  
  244.           
  245.         this.count = numberGumballs;  
  246.         // 若超过0颗糖果,就将状态设置为NoQuarterState  
  247.         if(numberGumballs > 0) {  
  248.             state = noQuarterState;  
  249.         }  
  250.     }  
  251.     // 取得机器内的糖果数目  
  252.     public int getCount() {  
  253.         return count;  
  254.     }  
  255.     // 取得糖果售罄状态  
  256.     public State getSoldOutState() {  
  257.         return soldOutState;  
  258.     }  
  259.     // 取得没有25分钱状态  
  260.     public State getNoQuarterState() {  
  261.         return noQuarterState;  
  262.     }  
  263.     // 取得拥有25分钱  
  264.     public State getHasQuarterState() {  
  265.         return hasQuarterState;  
  266.     }  
  267.     // 取得售出糖果状态  
  268.     public State getSoldState() {  
  269.         return soldState;  
  270.     }  
  271.     // 取得赢家状态  
  272.     public State getWinnerState() {  
  273.         return winnerState;  
  274.     }  
  275.     // 投入25分钱  
  276.     public void insertQuarter(){  
  277.         state.insertQuarter();  
  278.     }  
  279.     // 拒绝25分钱  
  280.     public void ejectQuarter(){  
  281.         state.ejectQuarter();  
  282.     }  
  283.     // 转动曲柄  
  284.     public void turnCrank(){  
  285.         state.turnCrank();  
  286.         state.dispense();  
  287.     }  
  288.     // 设置状态  
  289.     public void setState(State state){  
  290.         this.state=state;  
  291.     }  
  292.     // 糖果滚出来一个  
  293.     public void releaseBall(){  
  294.         System.out.println("A gumball comes rolling out of the solt...");  
  295.         if(count!=0){  
  296.             count--;  
  297.         }  
  298.     }  
  299. }  
  300.   
  301.   
  302. //测试糖果机的Java源文件 GumballMachineTestDrive.java  
  303. package State;  
  304. /* 
  305.  * 糖果机测试驱动程序:GumballMachineTestDrive.java 
  306.  */  
  307. public class GumballMachineTestDrive {  
  308.   
  309.     /** 
  310.      * @param args 
  311.      */  
  312.     public static void main(String[] args) {  
  313.         GumballMachine gumballMachine = new GumballMachine(5);  
  314.           
  315.         System.out.println(gumballMachine);  
  316.         System.out.println("The current gumball number is:" + gumballMachine.getCount());  
  317.         System.out.println("****************************************");  
  318.           
  319.           
  320.         gumballMachine.insertQuarter();  
  321.         gumballMachine.turnCrank();  
  322.           
  323.         System.out.println(gumballMachine);  
  324.         System.out.println("The current gumball number is:" + gumballMachine.getCount());  
  325.         System.out.println("****************************************");  
  326.           
  327.         gumballMachine.insertQuarter();  
  328.         gumballMachine.turnCrank();  
  329.         System.out.println(gumballMachine);   
  330.         System.out.println("The current gumball number is:" + gumballMachine.getCount());  
  331.         System.out.println("****************************************");  
  332.           
  333.         gumballMachine.insertQuarter();  
  334.         gumballMachine.turnCrank();  
  335.         System.out.println(gumballMachine);   
  336.         System.out.println("The current gumball number is:" + gumballMachine.getCount());  
  337.         System.out.println("****************************************");  
  338.     }  
  339.   
  340. }  

运行结果截图如下:



三、状态vs策略

       策略模式中,算法是由客户程序来决定context中所要组合的策略对象是哪一个,当然策略模式让我们具有弹性,能够在运行时动态改变策略。但对于某个context来说,通常只有一个最合适的策略对象。
  而状态模式如定义中所言,我们将一群行为封装在状态对象中,context的行为随时可以委托到那些状态对象中的一个,随着时间的进行,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此context的行为也会改变;对于客户程序来言,这种状态变化往往是透明的。

       我们把策略想象成除了继承以外的一种弹性替代方案,有了策略,你可以通过组合不同对象来改变行为。
       我们把状态模式想成是不用在context中放置许多条件判断的替代方案。通过将行为包装进状态对象中,你可以通过在context中简单的改变状态对象来改变context的行为。

ref:http://www.cnblogs.com/java-my-life/archive/2012/06/08/2538146.html
    http://blog.csdn.net/ccf19881030/article/details/8257659
    http://dev.yesky.com/438/2164938.shtml
原创粉丝点击