牛骨文教育服务平台(让学习变的简单)

我们是否在写程序的过程中有过在一个类中写了很多状态,是否需要根据该对象的不同状态决定该对象的不同行为。如:我们Android中自定义一个上拉加载更多,下拉刷新的RefreshListView呢?,我们在RefreshListView中定义了三中状态,即:下拉刷新状态,正在刷新,松开刷新,而且这三中不同的状态决定了该自定义控件是否可以下拉等行为,假如你没定义过该控件或者没有写个那种一个对象有多种状态对应控制多种行为也不要紧,因为状态模式很简单,我们只需要一个例子就知道怎么实现状态模式了。

定义:当一个对象内部状态改变时允许改变其行为,而不用根据不同的状态做过多的if-else判断,而是用不同的类代表不同状态下的行为,这不同的类可以之间不用相互依赖,各自代表不同状态下的行为。

状态模式使用场景:

  1. 一个对象的行为取决于它的状态,并且需要在运行的时候根据不同的状态改变行为。如:我们的RefreshListView,如果当前它的状态是正在刷新,那么它就不可下拉

  2. 代码中包含大量与对象状态相关的if-else语句,一个操作中含有大量的多分支语句if-else或者switch-case语句依赖于该对象的状态的情况,如果是这种情况,那么代码的可读性不好,且不易修改维护。

状态模式的优点:

  • 使程序的可扩展提高,易于维护。状态模式用一个状态行为类代表一种状态下个行为,摆脱了繁琐的状态判断行为,将繁琐的状态判断转换成结构清晰的状态类集。

状态模式的缺点:

  • 必然使得系统类和对象的个数增多。

代码实现:

电视机行为接口:

/**
 * 电视机行为
 * @author lt
 *
 */
public interface TvAction {
    public void startUp(); // 开机
    public void startOff(); // 关机
    public void nextChannel(); // 下一个频道
    public void prevChannel(); // 上一个频道
}

开机状态行为:

/**
 * 电视机开机状态下的行为
 * @author lt
 *
 */
public class TvStartUpState implements TvAction{

    /**
     * 开机,无效
     */
    @Override
    public void startUp() {

    }

    /**
     * 关机,有效
     */
    @Override
    public void startOff() {
        System.out.println("关机啦!");
    }

    /**
     * 下一个频道,无效
     */
    @Override
    public void nextChannel() {
        System.out.println("切换到下一个频道");
    }

    /**
     * 上一个频道,无效
     */
    @Override
    public void prevChannel() {
        System.out.println("切换到上一个频道");
    }

}

关机状态行为:

/**
 * 电视机关机状态下的行为
 * @author lt
 *
 */
public class TvStartOffState implements TvAction{

    /**
     * 开机,有效
     */
    @Override
    public void startUp() {
        System.out.println("开机啦!");
    }

    /**
     * 关机,无效
     */
    @Override
    public void startOff() {

    }

    /**
     * 下一个频道,无效
     */
    @Override
    public void nextChannel() {

    }

    /**
     * 上一个频道,无效
     */
    @Override
    public void prevChannel() {

    }

}

遥控器:

/**
 * 遥控器
 * @author lt
 *
 */
public class TvController implements TvAction{

    private TvAction tvStartUpState = new TvStartUpState();
    private TvAction tvStartOffState = new TvStartOffState();
    /**
     * 电视机的状态行为,状态即行为,默认为关机状态
     */
    private TvAction tvState = tvStartOffState;

    @Override
    public void startUp() {
        tvState.startUp();
        this.tvState = tvStartUpState;
    }

    @Override
    public void startOff() {
        tvState.startOff();
        this.tvState = tvStartOffState;
    }

    @Override
    public void nextChannel() {
        tvState.nextChannel();
    }

    @Override
    public void prevChannel() {
        tvState.prevChannel();
    }
}

测试:

public class Test {

    public static void main(String[] args) {
        TvController tvController = new TvController();
        // 开机
        tvController.startUp();
        tvController.nextChannel();
        tvController.prevChannel();

        // 关机
        tvController.startOff();
        tvController.nextChannel();
        tvController.prevChannel();

        // 开机
        tvController.startUp();
        // 关机
        tvController.startOff();
    }
}

结果:

这里写图片描述

状态模式模拟结束,上面我们测试的时候,我们对电视机的状态频繁切换,并操作了对应状态下的行为,达到了不同状态下对象的行为改变了。但你是否在上面所有的代码你有看到if-else或者switch-case?没有吧,事实上,状态模式就是为了避免过多的if-else和switch-case语句。上面模拟过程中我们看到了电视机的状态行为切换如此简单。

总结:

状态模式的出现就是为了解决一个对象多种状态下不同行为表现导致出现过多的if-else或者switch-case语句判断切换不同状态下的行为, 通常这种做法需要设置一个变量记录该对象当前的状态,然后根据变量执行不同的代码。而状态模式根本就不需要if-else和switch-case,一个对象类代表一种状态下的行为表现,当状态切换时切换不同的对象类即可,达到状态即行为的效果。状态模式的使用和没有使用状态模式的if-else/switch-case控制行为的关系有点像c是面向过程而java面向对象的关系一样。