java状态模式例子+分析

状态模式适用于自己的程序或者某个对象有几种不同的状态,每个状态下都有不同的操作,这样的情况下我们可以采用状态模式。

为什么要采用状态模式

在我们介绍状态模式之前,我们先想一想我们会怎么写。最正常的想法无非是在每个方法里面先判断当前对象处于什么状态,也就是说,要采用大量的if else语句或者switch语句。而这样可维护性上面就比较差,试想,如果后期我们需要增添或者减少一个状态,是不是每一处判断对象状态的代码块都要做出修改?为了避免这样的麻烦,我们可以采用状态模式。

先看一个例子

在这里插入图片描述
这是一张描述状态的转换图。可以看到,有四种状态,并且他们之间可以完成相互转换。我们看一看状态模式下的代码是什么样的。

1.抽象状态类的实现

public abstract class State {
    /**
     * 投币
     */
    public abstract void insertQuarter();

    /**
     * 退币
     */
    public abstract void ejectQuarter();

    /**
     * 转动出糖曲轴
     */
    public abstract void turnCrank();

    /**
     * 发糖
     */
    public abstract void dispense();

    /**
     * 退还硬币
     */
    protected void returnQuarter() {
        System.out.println("退币……");
    }
}

2.四个具体状态类的实现

/**
 * 没有硬币的状态
 */
public class NoQuarterState extends State{
    GumballMachine gumballMachine;

    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("你投入了一个硬币");
        //转换为有硬币状态
        gumballMachine.setState(gumballMachine.hasQuarterState);
    }

    @Override
    public void ejectQuarter() {
        System.out.println("没有硬币,无法弹出");
    }

    @Override
    public void turnCrank() {
        System.out.println("请先投币");
    }

    @Override
    public void dispense() {
        System.out.println("没有投币,无法发放糖果");
    }

}

/**
 * 投硬币的状态
 */
public class HasQuarterState extends State{
    GumballMachine gumballMachine;

    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("请不要重复投币!");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        returnQuarter();
        gumballMachine.setState(gumballMachine.noQuarterState);
    }

    @Override
    public void turnCrank() {
        System.out.println("转动曲轴,准备发糖");
        gumballMachine.setState(gumballMachine.soldState);
    }

    @Override
    public void dispense() {
        System.out.println("this method don't support");
    }

}

/**
 * 出售的状态
 */
public class SoldState extends State{
    GumballMachine gumballMachine;

    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("已投币,请等待糖果");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        System.out.println("无法退币,正在发放糖果,请等待");
    }

    @Override
    public void turnCrank() {
        System.out.println("已按过曲轴,请等待");
    }

    @Override
    public void dispense() {
        int candyCount = gumballMachine.getCandyCount();
        if(candyCount > 0){
            System.out.println("分发一颗糖果");
            candyCount--;
            gumballMachine.setCandyCount(candyCount);
            if(candyCount > 0){
                gumballMachine.setState(gumballMachine.noQuarterState);
                return;
            }
        }

        System.out.println("抱歉,糖果已售尽");
        gumballMachine.setState(gumballMachine.soldOutState);
    }

}

/**
 * 售尽的状态
 */
public class SoldOutState extends State{
    GumballMachine gumballMachine;

    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("糖果已经售尽");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        System.out.println("没有投币,无法退币");
    }

    @Override
    public void turnCrank() {
        System.out.println("糖果已经售尽");
    }

    @Override
    public void dispense() {
        System.out.println("糖果已经售尽");
    }

}

我们来分析一下这四个具体状态类的实现。首先,每一个具体类中,都有一个糖果机的引用。之所以有这个成员,是因为我们要通过这个成员来对我们的糖果机的状态进行更改。在看构造方法:传参为糖果机类型。之后我们看每个方法的具体实现。在不同的状态下,对应了不同的提示,以及状态的转换。
3.糖果机的实现

public class GumballMachine{
    public State noQuarterState = new NoQuarterState(this);
    public State hasQuarterState = new HasQuarterState(this);
    public State soldState = new SoldState(this);
    public State soldOutState = new SoldOutState(this);

    private State state = soldOutState;
    private int candyCount = 0;

    public GumballMachine(int count) {
        this.candyCount = count;
        if(count > 0)
            setState(noQuarterState);
    }

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

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

    public State getState() {
        return state;
    }

    public void setCandyCount(int candyCount) {
        this.candyCount = candyCount;
    }

    public int getCandyCount() {
        return candyCount;
    }

}

首先,可以清楚地看到,这里有许多表示状态的成员对象,这些就是用来表示状态以及做出特定状态下的动作的。此外还有一个public的State,这个状态是用来展示当前机器处于那种状态,前面的私有状态是不变的,而这个公有的state是在各个状态之前来回变化的。
至此,如果能定义好初始状态,那么我们调用糖果机里面的几种动作方法,就会调用state所指对象的方法,这样就能在糖果机不可见的地方实现了状态的切换。
这也就是状态模式的基本形式了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值