JAVA设计模式:状态模式 JAVA设计模式:状态模式

 转载:http://www.cnblogs.com/pony1223/p/7518226.htmlhtml

1、引出状态模式java

假设咱们如今有一个糖果机项目,那么咱们知道正常通常糖果机提供给用户的行为有这么几种:投入硬币、转动曲柄、退出硬币几种行为;那么糖果机呢通常有这几中状态,待机状态、持有硬币的准备状态、运行状态即正在售出状态和初始状态 这么几种正常状态。 咱们发现处于不一样状态的时候,持有的行为是不同的,图以下:算法

 

 

若是咱们采用传统的方法来写代码,那么在投入硬币这个行为操做的时候,咱们会进行状态的判断,只有在处于待机状态状况下这种行为是正常的,而其余则非正常,那么其余行为也同样,都须要去先判断下当前的状态来进行操做。获得的代码则为:设计模式

复制代码
  1 package study.designmode.statemode;
  2 
  3 public class CandyMachine {
  4 
  5     final static int SoldOutState = 0; //初始状态
  6     final static int OnReadyState = 1;  //待机状态
  7     final static int HasCoin = 2;  //准备状态
  8     final static int SoldState = 3;  //售出状态
  9 
 10     private int state = SoldOutState; //变量,用于存放当前的状态值
 11     private int count = 0; //糖果的数目
 12 
 13     public CandyMachine(int count) {
 14         this.count = count;
 15         if (count > 0) {
 16             state = OnReadyState;
 17         }
 18     }
 19 
 20     //投入硬币行为的时候,经过判断当前的状态来匹配全部的状态.
 21     public void insertCoin() {
 22         switch (state) {
 23         case SoldOutState:
 24             System.out.println("you can't insert coin,the machine sold out!");
 25             break;
 26         case OnReadyState: //只有在待机状态的时候,投入硬币行为正确,并将状态改变为准备状态
 27             state = HasCoin;
 28             System.out
 29                     .println("you have inserted a coin,next,please turn crank!");
 30             break;
 31         case HasCoin:
 32             System.out.println("you can't insert another coin!");
 33 
 34             break;
 35         case SoldState:
 36             System.out.println("please wait!we are giving you a candy!");
 37 
 38             break;
 39         }
 40 
 41     }
 42 
 43     //回退硬币
 44     public void returnCoin() {
 45         switch (state) {
 46         case SoldOutState:
 47             System.out
 48                     .println("you can't return,you haven't inserted a coin yet!");
 49             break;
 50         case OnReadyState:
 51             System.out.println("you haven't inserted a coin yet!");
 52             break;
 53         case HasCoin:
 54 
 55             System.out.println("coin return!");
 56             state = OnReadyState;
 57 
 58             break;
 59         case SoldState:
 60             System.out.println("sorry,you already have turned the crank!");
 61 
 62             break;
 63         }
 64 
 65     }
 66 
 67     //转动曲柄
 68     public void turnCrank() {
 69         switch (state) {
 70         case SoldOutState:
 71             System.out.println("you turned,but there are no candies!");
 72             break;
 73         case OnReadyState:
 74             System.out.println("you turned,but you haven't inserted a coin!");
 75             break;
 76         case HasCoin:
 77             System.out.println("crank turn...!");
 78             state = SoldState;
 79             dispense();
 80             break;
 81         case SoldState:
 82             System.out
 83                     .println("we are giving you a candy,turning another get nothing,!");
 84             break;
 85         }
 86 
 87     }
 88 
 89     //触发发放糖果行为
 90     private void dispense() {
 91         count = count - 1;
 92         System.out.println("a candy rolling out!");
 93         if (count > 0) {
 94             state = OnReadyState;
 95         } else {
 96             System.out.println("Oo,out of candies");
 97             state = SoldOutState;
 98         }
 99 
100     }
101 
102     public void printstate() {
103 
104         switch (state) {
105         case SoldOutState:
106             System.out.println("***SoldOutState***");
107             break;
108         case OnReadyState:
109             System.out.println("***OnReadyState***");
110             break;
111         case HasCoin:
112 
113             System.out.println("***HasCoin***");
114 
115             break;
116         case SoldState:
117             System.out.println("***SoldState***");
118             break;
119         }
120 
121     }
122 }
复制代码

那么上面这种方式存在什么问题呢?首先很直观的感觉就是:架构

1.存在大量的switch case 语句  固然能够用if  else 也是同样的。dom

 

2.可扩展性差,而且一旦要加入一种新的状态,那么就会要修改全部的switch case  不符合开闭原则ide

3.没有采用面向对象的方式去封装post

好比,这个时候,新增长了一种状态,赢家状态,便可以获取到两粒糖果;那么若是用上面的方式,确定是不符合开闭原则的,同时扩展性也是很差的;那么咱们有什么其它的方式来解决呢?测试

 

2、解决办法this

为了解决上面的问题,咱们首先分析项目中变化的部分和不变的部分,抽化出变化的部分,咱们发现糖果机提供的行为通常是不变的,就是投入硬币、转动曲柄给、退回硬币、机器发放糖果;而糖果机的状态是能够变化的,能够新增出一种状态来,好比咱们说的赢家状态。那么咱们这个抽出变化的部分,即咱们说的状态,因而出现了下面的结构设计方案:

 

这个结构图告诉咱们,提炼出状态接口出来,而后将各个状态抽出,并去实现接口,每一个状态都持有投入硬币,退回硬币,转动曲柄、售出糖果这几种行为对应的方法作出相应;而糖果机持有全部的状态,并经过引用状态接口来操做各个状态;这种设计架构就是咱们说的状态模式。

状态模式定义:对象行为的变化是因为状态的变化引入,那么即当内部状态发生变化的时候,就会改变对象的行为,而这种改变视乎就改变了整个类。

那么如今采用状态模式来解决问题:

1.首先定义接口:

 

复制代码
package study.designmode.statemode.state;

public interface State {
    public void insertCoin();
    public void returnCoin();
    public void turnCrank();
    public void dispense();
    public void printstate();
}
复制代码

 

2.定义各个状态的实现类

准备状态:

复制代码
package study.designmode.statemode.state;

import java.util.Random;

public class HasCoin implements State {
    private CandyMachine mCandyMachine;

    public HasCoin(CandyMachine mCandyMachine) {
        this.mCandyMachine = mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("you can't insert another coin!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("coin return!");
        mCandyMachine.setState(mCandyMachine.mOnReadyState);
    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("crank turn...!");
        Random ranwinner=new Random();
        int winner=ranwinner.nextInt(10);
        if(winner==0)
        {
            mCandyMachine.setState(mCandyMachine.mWinnerState);

        }else
        {
            mCandyMachine.setState(mCandyMachine.mSoldState);

        }
        
    }

    @Override
    public void dispense() {
    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***HasCoin***");

    }

}
复制代码

 

说明:咱们会发现里面存在一个糖果机的属性,而之因此存在这个属性,就是由于糖果机中持有全部的状态,而在准备状态下,确定会因为某种行为发生状态改变,而要改变的状态都在糖果机中,因此持有一个糖果机属性,下面也同样,不在重复说明。

准备状态:

复制代码
package study.designmode.statemode.state;

public class OnReadyState implements State {
    private CandyMachine mCandyMachine;
    public OnReadyState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out
        .println("you have inserted a coin,next,please turn crank!");
        mCandyMachine.setState(mCandyMachine.mHasCoin);
    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");
        
    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("you turned,but you haven't inserted a coin!");
        
    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***OnReadyState***");
        
    }

}
复制代码

 

初始状态:

复制代码
package study.designmode.statemode.state;

public class SoldOutState implements State {

    private CandyMachine mCandyMachine;
    public SoldOutState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("you can't insert coin,the machine sold out!");
        
    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out
        .println("you can't return,you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out.println("you turned,but there are no candies!");
        
    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***SoldOutState***");
    
    }

}
复制代码

 

售出状态:

 

复制代码
package study.designmode.statemode.state;

public class SoldState implements State {
    private CandyMachine mCandyMachine;
    public SoldState(CandyMachine mCandyMachine)
    {
        this.mCandyMachine=mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("please wait!we are giving you a candy!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");
        
    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out
        .println("we are giving you a candy,turning another get nothing,!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub
        
        mCandyMachine.releaseCandy();
        if (mCandyMachine.getCount() > 0) {
            mCandyMachine.setState(mCandyMachine.mOnReadyState);
        } else {
            System.out.println("Oo,out of candies");
            mCandyMachine.setState(mCandyMachine.mSoldOutState);
        }

    
    
    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***SoldState***");
        
    }

}
复制代码

 

赢家状态:

复制代码
package study.designmode.statemode.state;

public class WinnerState implements State {

    private CandyMachine mCandyMachine;

    public WinnerState(CandyMachine mCandyMachine) {
        this.mCandyMachine = mCandyMachine;
    }

    @Override
    public void insertCoin() {
        // TODO Auto-generated method stub
        System.out.println("please wait!we are giving you a candy!");

    }

    @Override
    public void returnCoin() {
        // TODO Auto-generated method stub
        System.out.println("you haven't inserted a coin yet!");

    }

    @Override
    public void turnCrank() {
        // TODO Auto-generated method stub
        System.out
                .println("we are giving you a candy,turning another get nothing,!");

    }

    @Override
    public void dispense() {
        // TODO Auto-generated method stub

        
        mCandyMachine.releaseCandy();
        if (mCandyMachine.getCount() == 0) {
            mCandyMachine.setState(mCandyMachine.mSoldOutState);
        } else {
            System.out.println("you are a winner!you get another candy!");
            mCandyMachine.releaseCandy();
            if (mCandyMachine.getCount() > 0) {
                mCandyMachine.setState(mCandyMachine.mOnReadyState);
            } else {
                System.out.println("Oo,out of candies");
                mCandyMachine.setState(mCandyMachine.mSoldOutState);
            }
        }

    }

    @Override
    public void printstate() {
        // TODO Auto-generated method stub
        System.out.println("***WinnerState***");

    }

}
复制代码

 

3.糖果机,糖果机要持有全部的状态,并在初始化的时候,要设置其开始的状态,而后糖果的各个行为,就委托到了各个状态中本身维护,代码以下:

复制代码
package study.designmode.statemode.state;

public class CandyMachine {

    State mSoldOutState;
    State mOnReadyState;
    State mHasCoin;
    State mSoldState;
    State mWinnerState;
    private State state;
    private int count = 0;

    public CandyMachine(int count) {
        this.count = count;
        mSoldOutState = new SoldOutState(this);
        mOnReadyState = new OnReadyState(this);
        mHasCoin = new HasCoin(this);
        mSoldState = new SoldState(this);
        mWinnerState = new WinnerState(this);
        if (count > 0) {
            state = mOnReadyState;
        } else {
            state = mSoldOutState;
        }
    }

    public void setState(State state) {
        this.state = state;
    }

    public void insertCoin() {
        state.insertCoin();
    }

    public void returnCoin() {
        state.returnCoin();
    }

    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void releaseCandy() {

        // TODO Auto-generated method stub
        if (count > 0) {
            count = count - 1;
            System.out.println("a candy rolling out!");
        }

    }

    public int getCount() {
        return count;
    }

    public void printstate() {
        state.printstate();
    }
}
复制代码

 

4.测试类

复制代码
package study.designmode.statemode.state;

public class MainTest {
    public static void main(String[] args) {
        CandyMachine mCandyMachine = new CandyMachine(6);

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();

        mCandyMachine.insertCoin();
        mCandyMachine.printstate();

        mCandyMachine.turnCrank();

        mCandyMachine.printstate();
    }
}
复制代码

 

结果以下:

 

能够和开始的传统方案对比,结果是同样的,可是具有了可扩展性。

 

3、总结

经过上面的例子,咱们已经对状态模式有所了解,下面咱们作一个总结,来回顾咱们的状态模式:

1.状态模式容许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
   理解:这个模式将状态封装成独立的类,并将动做委托到表明当前状态的对象,这就是说行为会随着内部状态而改变。
   “看起来好像修改了它的类”是什么意思呢?从客户的视角来看:若是说你使用的对象可以彻底改变它的行为,那么你会以为,这个对象其实是从别的类实例化而来的。然而,实际上,你知道咱们是在使用组合经过简单引用不一样的状态对象来形成类改变的假象

2.状态模式要点

(1)客户不会和状态进行交互,全盘了解状态是 context的工做
(2)在状态模式中,每一个状态经过持有Context的引用,来实现状态转移
(3)使用状态模式老是会增长设计中类的数目,这是为了要得到程序可扩展性,弹性的代价,若是你的代码不是一次性的,后期可能会不断加入不一样的状态,那么状态模式的设计是绝对值得的。【同时也是一个缺点】
(4)状态类能够被多个context实例共享

3.状态模式和策略模式对比

首先让咱们来看看它们之间更多的类似之处:
添加新的状态或策略都很容易,并且不须要修改使用它们的Context对象。
它们都让你的代码符合OCP原则(软件对扩展应该是开发的,对修改应该是关闭的)。在状态模式和策略模式中,Context对象对修改是关闭的,添加新的状态或策略,都不须要修改Context。
正如状态模式中的Context会有初始状态同样,策略模式一样有默认策略。
状态模式以不一样的状态封装不一样的行为,而策略模式以不一样的策略封装不一样的行为。
它们都依赖子类去实现相关行为

两个模式的差异在于它们的”意图“不一样:

状态模式帮助对象管理状态,咱们将一群行为封装早状态对象中,context的行为随时可委托到那些状态中的一个.随着时间的流逝,当前状态在状态对象集合中游走改变,以反映context内部状态,所以,context的行为也会跟着改变。当要添加新的状态时,不须要修改原来代码添加新的状态类便可。 而策略模式容许Client选择不一样的行为。经过封装一组相关算法,为Client提供运行时的灵活性。Client能够在运行时,选择任一算法,而不改变使用算法的Context。一些流行的策略模式的例子是写那些使用算法的代码,例如加密算法、压缩算法、排序算法。客户一般主动指定context所要组合的策略对象是哪个.

一句话:最根本的差别在于策略模式是在求解同一个问题的多种解法,这些不一样解法之间毫无关联;状态模式则不一样,状态模式要求各个状态之间有所关联,以便实现状态转移。

 
相关文章
相关标签/搜索