美文网首页技术干货程序员
Java 设计模式(12) —— 状态模式

Java 设计模式(12) —— 状态模式

作者: 磊_lei | 来源:发表于2018-05-22 23:21 被阅读222次

    一、状态模式

    能根据内部状态的变化,改变对象的行为,看起来好像修改了类

    状态模式

    二、示例

    智能糖果机:需要设计一款自助购买的糖果机,糖果机的状态有

    • 准备使用(接下来可投入硬币)
    • 投入硬币(接下来可摇动把手或者退出硬币)
    • 售出糖果(接下来可恢复使用或者售罄)
    • 售罄状态

    使用传统的面向对象模式,只需定义一个糖果机的对象,内部根据不同的状态进行不同的操作处理

    
    /**
     * 面向对象模式,糖果机
     */
    public class CandyMachine {
    
        final static int SoldOutState = 0;          // 售罄状态
        final static int OnReadyState = 1;          // 准备售出状态
        final static int HasCoin = 2;               // 已经投了硬币的状态
        final static int SoldState = 3;             // 售出状态
    
        private int state = SoldOutState;
        private int count = 0;                      // 内部糖果的剩余数量
    
        public CandyMachine(int count) {
            this.count = count;
            if (count > 0) {
                state = OnReadyState;
            }
        }
    
        /**
         * 投入硬币,如果糖果机状态是准备售出,则可以摇动把手购买糖果,其他的状态则无法使用
         */
        public void insertCoin() {
            switch (state) {
                case SoldOutState:
                    System.out.println("you can't insert coin,the machine sold out!");
                    break;
                case OnReadyState:
                    state = HasCoin;
                    System.out
                            .println("you have inserted a coin,next,please turn crank!");
                    break;
                case HasCoin:
                    System.out.println("you can't insert another coin!");
    
                    break;
                case SoldState:
                    System.out.println("please wait!we are giving you a candy!");
    
                    break;
            }
    
        }
    
        /**
         * 如果已经投入硬币之后则可以选择退出硬币
         */
        public void returnCoin() {
            switch (state) {
                case SoldOutState:
                    System.out
                            .println("you can't return,you haven't inserted a coin yet!");
                    break;
                case OnReadyState:
                    System.out.println("you haven't inserted a coin yet!");
                    break;
                case HasCoin:
    
                    System.out.println("coin return!");
                    state = OnReadyState;
    
                    break;
                case SoldState:
                    System.out.println("sorry,you already have turned the crank!");
    
                    break;
            }
    
        }
    
        /**
         * 如果已经投入硬币则可以摇动把手
         */
        public void turnCrank() {
            switch (state) {
                case SoldOutState:
                    System.out.println("you turned,but there are no candies!");
                    break;
                case OnReadyState:
                    System.out.println("you turned,but you haven't inserted a coin!");
                    break;
                case HasCoin:
                    System.out.println("crank turn...!");
                    state = SoldState;
                    dispense();
                    break;
                case SoldState:
                    System.out.println("we are giving you a candy,turning another get nothing,!");
                    break;
            }
    
        }
    
        /**
         * 掉出糖果
         */
        private void dispense() {
            count--;
            System.out.println("a candy rolling out!");
            if (count > 0) {
                state = OnReadyState;
            } else {
                System.out.println("Oo,out of candies");
                state = SoldOutState;
            }
    
        }
    
        public void printstate() {
    
            switch (state) {
                case SoldOutState:
                    System.out.println("***SoldOutState***");
                    break;
                case OnReadyState:
                    System.out.println("***OnReadyState***");
                    break;
                case HasCoin:
                    System.out.println("***HasCoin***");
    
                    break;
                case SoldState:
                    System.out.println("***SoldState***");
                    break;
            }
    
        }
    }
    

    缺点:各种行为耦合度较高,不利于新需求的拓展

    三、状态模式改进

    虽然传统的面向对象模式也可满足功能,但是若新增需求则不利于拓展。加入此项目新增一个幸运者的功能,售出糖果的时候有一定几率成为幸运者掉出两颗糖果。

    若满足该功能,则需在原本完成的糖果机代码中修改,则易造成其他不必要的bug,则引出状态模式:

    • 定义一个状态接口,接口定义需要处理的方法
    • 定义不同状态的接口对象,对象内实现不同状态对不同操作的处理
    
    /**
     * 状态模式,统一的状态接口,接口内实现不同状态下不同的处理行为
     */
    public interface State {
    
        // 投入硬币
        public void insertCoin();
    
        // 退出硬币
        public void returnCoin();
    
        // 摇动把手
        public void turnCrank();
    
        // 掉出糖果
        public void dispense();
    
        // 打印当前状态
        public void printstate();
    }
    
    
    /**
     * 状态模式,新增的幸运者状态,出糖果的时候有一定概率出两颗
     */
    public class WinnerState implements State {
    
        private CandyMachine mCandyMachine;
    
        public WinnerState(CandyMachine mCandyMachine) {
            this.mCandyMachine = mCandyMachine;
        }
    
        @Override
        public void insertCoin() {
            System.out.println("please wait!we are giving you a candy!");
    
        }
    
        @Override
        public void returnCoin() {
            System.out.println("you haven't inserted a coin yet!");
    
        }
    
        @Override
        public void turnCrank() {
            System.out.println("we are giving you a candy,turning another get nothing,!");
    
        }
    
        @Override
        public void dispense() {
            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() {
            System.out.println("***WinnerState***");
        }
    
    }
    
    
    /**
     * 状态模式,糖果机内只定义状态接口对象,在接口内部给糖果机的状态赋值
     */
    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() {
            if (count > 0) {
                count = count - 1;
                System.out.println("a candy rolling out!");
            }
    
        }
    
        public int getCount() {
            return count;
        }
    
        public void printstate() {
            state.printstate();
        }
    }
    
    
    /**
     * 状态模式,通过定义一个状态接口,接口内实现不同状态下不同的处理方式
     * 则调用处理方式时直接调用状态接口对象的实现方法
     * 使用状态模式可以是不同状态接互不影响,也可便于新增多种状态类型的需求
     */
    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();
        }
    }
    

    四、总结

    在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

    Java设计模式所有示例代码,持续更新中

    相关文章

      网友评论

        本文标题:Java 设计模式(12) —— 状态模式

        本文链接:https://www.haomeiwen.com/subject/zhcljftx.html