状态模式(State Pattern)

本文深入解析状态模式,探讨如何利用类表示状态,避免复杂的条件判断,实现对象在不同状态下的行为变化。通过饮水机实例,展示状态模式的实现过程及优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用类表示状态

1.基本介绍

状态模式使用对象的形式来记录某种状态。使用状态模式可以省去多个if-else或者是switch的判断。可以直接使用对象方法的形式来处理逻辑。

我们在编写代码的时候,遇到大量的条件判断的时候,可能会采用策略模式来优化结构,因为这时涉及到策略的选择,但有时候仔细查看下,就会发现,这些所谓的策略其实是对象的不同状态,更加明显的是,对象的某种状态也成为判断的条件


2.实例分析

假设现在我们有一个饮水机,它有以下两个状态: 满桶,空桶。初始状态是满桶,容量是20。饮水机只有一个动作:press,每次press后都会使容量减1,一旦为0,则将状态设置为空桶,这时press没有水流出。

要使用状态模式,我们必须明确两个东西:状态和每个状态下执行的动作。就像是饮水机,最基本的状态就是满桶和空桶,而这两个状态下,都可能要执行倒水这个动作,也就是press。如果饮水机的容量为0,则会进入空桶的状态。

在状态模式中,因为所有的状态都要执行相应的动作,所以我们可以考虑将状态抽象出来。
状态的抽象一般有两种形式:接口和抽象类。如果所有的状态都有共同的数据域,可以使用抽象类,但如果只是单纯的执行动作,就可以使用接口。

接口:

public interface DispenserState {
    void press();
}

定义满桶和空桶两个状态

/**
 * @author Jay
 * @date 2019/6/5 22:40
 * @description 空桶
 */
public class NullState implements  DispenserState {
    @Override
    public void press() {
        System.out.println("There is not water poured!");
    }
}
/**
 * @author Jay
 * @date 2019/6/5 22:39
 * @description 满桶
 */
public class FullState implements DispenserState {
    @Override
    public void press() {
        System.out.println("Water is pouring!");

    }
}

实现饮水机

/**
 * @author Jay
 * @date 2019/6/5 22:41
 * @description 实现饮水机
 */
public class WaterDispenser {
    private static int capacity = 20;
    private static DispenserState dispenserState;

    public WaterDispenser(DispenserState state) {
        dispenserState = state;
    }

    private static void setState(DispenserState state) {
        dispenserState = state;
    }

    public DispenserState getState() {
        return dispenserState;
    }

    public void press() {
        capacity--;
        if (capacity <= 0) {
            // 只需要改变状态即可
            setState(new NullState());
        }
        dispenserState.press();
    }
}

测试:

   /**
 * @author Jay
 * @date 2019/6/5 22:49
 * @description
 */
public class Test {
    public static void main(String[] args) {
        WaterDispenser dispenser = new WaterDispenser(new FullState());
        for (int i = 0; i < 100; ++i) {
            dispenser.press();
        }
    }
}

状态模式的好处就是将我们从这个复杂的嵌套条件中脱离出来,但状态模式的坏处也是非常明显:需要管理一系列的状态类

状态模式的意图就是让每一个状态对修改关闭,允许对象在内部状态改变时改变它的行为,使对象看起来好像修改了它的类。

让每一个状态对修改关闭,也就是让状态类来改变状态,即封装,我们只能通过向状态类发送消息来改变状态,至于怎么改变,则完全隐藏起来。

允许对象在内部状态改变时改变它的行为,使对象看起来好像修改了它的类。其实,对象本身拥有一个状态类的对象集合,只要符合状态改变的条件,就可以将表示状态的状态类改变成下个状态类。从具体的代码来看,所谓的状态类的对象集合,其实就是我们的对象拥有一个状态类的引用,该引用可以指向任何状态类的对象集合的具体引用。对象本身一般都会有一个setState()方法,可以将状态修改成另一个状态

状态模式的意图其实非常简单:将与状态有关的处理逻辑分散到代表对象状态的各个类中,但我们的Context类必须拥有这些状态对象集合的引用,这也就引出一个问题:实例化Context类对象会导致状态类对象集合初始化方面的问题,也就是对象的依赖问题。

为了尽可能减少这方面的依赖,我们的Context类通常拥有的只是一个状态类的抽象引用,然后设置一个setter以便动态的更改状态类对象

如果不是使用对象,而是采用常量的方法。

private static final int FULL_STATE = 0;
private static final int NULL_STATE = 1;

enum STATE{ NULL_STATE, FULL_STATE};

4.模式总结

State(状态)

State角色表示状态,定义了根据不同状态进行不同处理的接口(API)。该接口(API)是那些处理内容依赖于状态的方法的集合。

ConcreteState(具体状态)

ConcreteState角色表示各个具体的状态,它实现了State接口。

Context(状况、前后关系、上下文)

Context角色持有表示当前状态的ConcreteState角色。此外,它还定义了供外部调用者使用State模式的接口(API)。


To GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值