前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式 | 行为型 | 状态模式

设计模式 | 行为型 | 状态模式

作者头像
被水淹没
发布2023-02-25 19:15:52
2380
发布2023-02-25 19:15:52
举报
文章被收录于专栏:迈向架构师迈向架构师

状态模式(State)

状态模式(State)

介绍

状态模式是一种行为设计模式

状态模式能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。

有限状态机的概念紧密相关。

状态机由 3 个部分组成:状态事件(转移条件)、动作。事件触发状态的转移及动作的执行。

适用场景

  • 对象需要根据当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更。
  • 某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句。
  • 当相似状态和基于条件的状态机转换中存在许多重复代码。
  • ...

优缺点

优点:

  • 开闭原则。
  • 单一职责原则。
  • 通过消除臃肿的状态机条件语句简化上下文代码。

缺点:

  • 复杂度增加:如果状态机只有很少的几个状态,使用状态模式会很复杂。

与其他模式的关系

  • 状态可被视为策略的扩展
    • 策略模式中的策略则几乎完全不知道其他策略的存在。
    • 状态模式中,特定状态知道其他所有状态的存在,且能触发从一个状态到另一个状态的转换。

实现方式

  1. 声明状态接口
  2. 为每个实际状态创建一个继承状态接口的类。
  3. 在上下文类中添加一个状态接口类型的引用成员变量,以及一个用于修改该成员变量值的公有设置器
  4. 为切换上下文状态,你需要创建某个状态类实例并将其传递给上下文
    • 可以在上下文、各种状态或客户端中完成这项工作。无论在何处完成这项工作,该类都将依赖于其所实例化的具体类。
    • 如果状态类中不包含成员变量,则可以使用单例模式来配合使用。

其他实现方法: 分支逻辑法:直接利用 if 逻辑或者 switch 分支逻辑,直接写状态转移的代码。适合简单直接的状态机。 查表法:通过二维数组来表示状态转移图,能极大地提高代码的可读性和可维护性。适合状态较多、转移复杂的状态机。

示例

状态接口

代码语言:javascript
复制
public abstract class State {

    Kettle kettle;

    public State(Kettle kettle) {
        this.kettle = kettle;
    }

    // 动作

    // 加水
    public abstract String addWater();
    // 煮水
    public abstract String boilWater();
    // 倒水
    public abstract String pourWater();
}

状态实现

代码语言:javascript
复制
public class EmptyState extends State {

    public EmptyState(Kettle kettle) {
        super(kettle);
    }

    @Override
    public String addWater() {
        // 切换上下文状态
        kettle.changeState(new ColdState(kettle));
        return "加水成功";
    }
    @Override
    public String boilWater() {
        return "没水...";
    }
    @Override
    public String pourWater() {
        return "没水...";
    }

    @Override
    public String toString() {
        return "空的状态";
    }
}

public class ColdState extends State {

    public ColdState(Kettle kettle) {
        super(kettle);
    }

    @Override
    public String addWater() {
        return "有水了,别加了";
    }
    @Override
    public String boilWater() {
        // 切换上下文状态
        kettle.changeState(new BoilingState(kettle));
        return "煮水成功";
    }
    @Override
    public String pourWater() {
        // 切换上下文状态
        kettle.changeState(new EmptyState(kettle));
        return "倒水成功(冷水)";
    }

    @Override
    public String toString() {
        return "冷水状态";
    }
}

public class BoilingState extends State {

    public BoilingState(Kettle kettle) {
        super(kettle);
    }

    @Override
    public String addWater() {
        return "有水了,别加了";
    }
    @Override
    public String boilWater() {
        return "保温中...";
    }
    @Override
    public String pourWater() {
        // 切换上下文状态
        kettle.changeState(new EmptyState(kettle));
        return "倒水成功(开水)";
    }

    @Override
    public String toString() {
        return "热水状态";
    }
}

上下文(热水壶类)

代码语言:javascript
复制
public class Kettle {

    // 保存一个指向表示当前状态的状态对象的引用
    private State state;

    // ... 这里也可以存放一些其他数据,如水量水温等。

    public Kettle() {
        this.state = new EmptyState(this);
    }
    
    public State getState() {
        return state;
    }

    // 公有设置器
    public void changeState(State state) {
        this.state = state;
    }

    // 将执行工作委派给当前状态 x3
    public String addWater() {
        return state.addWater();
    }
    public String boilWater() {
        return state.boilWater();
    }
    public String pourWater() {
        return state.pourWater();
    }
}

测试代码

代码语言:javascript
复制
public class StateTest {
    @Test
    public void test() {
        
        Kettle kettle = new Kettle();

        Assertions.assertEquals("空的状态", kettle.getState().toString());

        Assertions.assertEquals("没水...", kettle.pourWater());
        Assertions.assertEquals("加水成功", kettle.addWater());

        Assertions.assertEquals("冷水状态", kettle.getState().toString());

        Assertions.assertEquals("有水了,别加了", kettle.addWater());
        Assertions.assertEquals("煮水成功", kettle.boilWater());

        Assertions.assertEquals("热水状态", kettle.getState().toString());

        Assertions.assertEquals("有水了,别加了", kettle.addWater());
        Assertions.assertEquals("保温中...", kettle.boilWater());
        Assertions.assertEquals("倒水成功(开水)", kettle.pourWater());

        Assertions.assertEquals("空的状态", kettle.getState().toString());
    }
}

以上代码与文章会同步到 github 仓库:

/chenbihao/Design-Patterns

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 迈向架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 状态模式(State)
    • 介绍
      • 适用场景
        • 优缺点
          • 与其他模式的关系
            • 实现方式
              • 示例
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档