zoukankan      html  css  js  c++  java
  • 状态模式

    1.定义

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

    和策略模式有点像,都是封装了行为,不同的是状态模式多了状态,根据不同的状态来实行不同的行为.

    2.代码实现

    以糖果机为例子,糖果机分别对应 1. 没有钱 2. 有钱 3. 售出糖果 4. 糖果售罄 5. 胜利者 这四种状态,以及 1. 投入钱 2. 转动曲柄 3. 退回25分钱 4. 发放糖果 这四种行为

    因为每种状态对应的糖果机行为都不一样,我们直接使用状态模式来实现

    定义 状态类 State

    package state;
    
    public interface State {
        /**
         * 投钱
         */
        void insertQuarter();
        /**
         * 退钱
         */
        void ejectQuarter();
        /**
         * 转动曲柄
         */
        void turnCrank();
        /**
         * 发放糖果
         */
        void dispense();
        
    }

    状态接口中定义了四种行为,我们可以实现不同的状态来实现每种状态对应的行为

    定义没有钱 状态

    package state;
    
    public class NoQuarterState implements State {
        GumballMachine gumballMachine;
    
        public NoQuarterState(GumballMachine gumballMachine) {
            super();
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("You inserted a quarter");
            gumballMachine.setState(gumballMachine.getHasQuarterState());
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("You havent't inserted a quarter");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("You turned, but there's no quarter");
        }
    
        @Override
        public void dispense() {
            System.out.println("You need to pay first");
        }
    
        @Override
        public String toString() {
            return "NoQuarterState []";
        }
        
    }

    在insertQuarter方法中,我们投入钱后会改变状态为HasQuarterState

    定义有钱状态

    package state;
    
    import java.util.Random;
    
    public class HasQuarterState implements State{
        Random randomWinner = new Random(System.currentTimeMillis());
        GumballMachine gumballMachine;
        
        
        public HasQuarterState(GumballMachine gumballMachine) {
            super();
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("You can't insert another quarter");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("Quarter returned");
            gumballMachine.setState(gumballMachine.getNoQuarterState());
        }
    
        @Override
        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());
            }
        }
    
        @Override
        public void dispense() {
            System.out.println("No gumball dispensed");
        }
    
        @Override
        public String toString() {
            return "HasQuarterState []";
        }
        
    }

    当投入钱后我们需要转动手柄摇出糖果,这边多了一个状态叫做胜利者状态,当随机数为0的时候会发送两颗糖果

    定义贩卖状态

    package state;
    
    public class SoldState  implements State{
        GumballMachine gumballMachine;
    
        public SoldState(GumballMachine gumballMachine) {
            super();
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("Please wait, we're already giving you a gumball");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("Sorry, you already turned the crank");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("Turning twice doesn't get you another gumball!");
        }
    
        @Override
        public void dispense() {
            gumballMachine.releaseBall();
            if (gumballMachine.getCount() > 0) {
                gumballMachine.setState(gumballMachine.getNoQuarterState());
            } else {
                System.out.println("Oops, out of gumballs!");
                gumballMachine.setState(gumballMachine.getSoldOutState());
            }
        }
    
        @Override
        public String toString() {
            return "SoldState []";
        }
        
    }

    在dispense方法中,当发出糖果后,糖果数量为0则设置为SoldOut售罄状态,否则设置为NoQuarter状态,等待下一次投钱.

    定义SoldOut售罄状态

    package state;
    
    public class SoldOutState implements State{
        GumballMachine gumballMachine;
    
        public SoldOutState(GumballMachine gumballMachine) {
            super();
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("no gumball");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("no gumball");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("no gumball");
        }
    
        @Override
        public void dispense() {
            System.out.println("no gumball");
        }
    
        @Override
        public String toString() {
            return "SoldOutState []";
        }
        
    }

    售罄状态的四种行为不会执行任何操作,因为没有糖果,需要等待投入糖果后才能改变这个状态,但是这里没有实现投入糖果这种行为.

    定义胜利者状态

    package state;
    
    public class WinnerState implements State{
        GumballMachine gumballMachine;
    
        public WinnerState(GumballMachine gumballMachine) {
            super();
            this.gumballMachine = gumballMachine;
        }
    
        @Override
        public void insertQuarter() {
            System.out.println("error");
        }
    
        @Override
        public void ejectQuarter() {
            System.out.println("error");
        }
    
        @Override
        public void turnCrank() {
            System.out.println("error");
        }
    
        @Override
        public void dispense() {
            System.out.println("You're a winner! You get two gumballs for your quarter");
            gumballMachine.releaseBall();
            if (gumballMachine.getCount() == 0) {
                gumballMachine.setState(gumballMachine.getSoldOutState());
            } else {
                gumballMachine.releaseBall();
                if (gumballMachine.getCount() == 0) {
                    gumballMachine.setState(gumballMachine.getSoldOutState());
                } else {
                    System.out.println("Oops, out of gumballs!");
                    gumballMachine.setState(gumballMachine.getSoldOutState());
                }
            }
        }
    
        @Override
        public String toString() {
            return "WinnerState []";
        }
        
        
    }

    在dispense方法中,我们发放两颗糖果,并且通过每次发完糖果都要判断是否为0,所以if else 多一些.

    接下来定义糖果机,因为使用了状态模式,所以代码简洁一点,因为实现都封装在了各自的State状态中.直接根据每种状态调用行为即可.

    package state;
    
    import java.util.concurrent.SynchronousQueue;
    
    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;
            if (numberGumballs > 0) {
                state = noQuarterState;
            }
        }
        
        public void insertQuarter() {
            state.insertQuarter();
        }
        
        public void ejectQuarter() {
            state.ejectQuarter();
        }
        
        public void turnCrank() {
            state.turnCrank();
            state.dispense();
        }
        
        public void releaseBall() {
            System.out.println("A gumball come rolling out the slot...");
            if (count != 0) {
                count--;
            }
        }
        
        public State getSoldOutState() {
            return soldOutState;
        }
    
        public void setSoldOutState(State soldOutState) {
            this.soldOutState = soldOutState;
        }
    
        public State getNoQuarterState() {
            return noQuarterState;
        }
    
        public void setNoQuarterState(State noQuarterState) {
            this.noQuarterState = noQuarterState;
        }
    
        public State getHasQuarterState() {
            return hasQuarterState;
        }
    
        public void setHasQuarterState(State hasQuarterState) {
            this.hasQuarterState = hasQuarterState;
        }
    
        public State getSoldState() {
            return soldState;
        }
    
        public void setSoldState(State soldState) {
            this.soldState = soldState;
        }
    
        public State getState() {
            return state;
        }
    
        public void setState(State state) {
            this.state = state;
        }
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public State getWinnerState() {
            return winnerState;
        }
    
        public void setWinnerState(State winnerState) {
            this.winnerState = winnerState;
        }
    
        @Override
        public String toString() {
            return "GumballMachine [state=" + state + ", count=" + count + "]";
        }
        
        
    }

    测试类

    package state;
    
    public class GumballMachineTestDriver {
        public static void main(String[] args) {
            GumballMachine gumballMachine = new GumballMachine(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);
        }
    }
    GumballMachine [state=NoQuarterState [], count=5]
    You inserted a quarter
    You turned...
    A gumball come rolling out the slot...
    GumballMachine [state=NoQuarterState [], count=4]
    You inserted a quarter
    You turned...
    You're a winner! You get two gumballs for your quarter
    A gumball come rolling out the slot...
    A gumball come rolling out the slot...
    Oops, out of gumballs!
    no gumball
    no gumball
    no gumball
    GumballMachine [state=SoldOutState [], count=2]

     

    3.总结

    状态模式和策略差不多,只是多了状态而已,如果没有状态的改变建议还是使用策略模式,而且状态可以在 Context (也就是我们定义的糖果机) 中改变,也可以在定义的状态中改变,这里因为业务需要在运行时改变,所以定义在State中会好一些.

  • 相关阅读:
    VS2013无法启动 IIS Express Web解决办法
    浅谈Java中switch分支语句
    instanceof运算符与引用变量的强制类型转换
    Java语言中null与" "的区别
    Java字符串无意识的递归
    不同编程语言实现输出“HelloWorld!”
    用 C# 来守护 Python 进程
    Python核心技术与实战 笔记
    Python3 系列之 并行编程
    Django + Gunicorn + Nginx 部署之路
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/11299940.html
Copyright © 2011-2022 走看看