深入理解设计模式之状态模式

news2025/6/2 9:26:38

深入理解设计模式之:状态模式(State Pattern)

一、什么是状态模式?

状态模式(State Pattern)是一种行为型设计模式。它允许一个对象在其内部状态发生改变时,改变其行为(即表现出不同的行为)。状态模式将与状态相关的行为封装到独立的状态类中,并通过状态切换来改变对象的行为。

核心思想:
将状态的切换和行为的变化解耦,使得状态切换变得灵活,代码结构清晰,易于扩展和维护。


二、状态模式的应用场景

  • 对象的行为依赖于它的状态,并且在运行时根据状态发生改变
  • 代码中包含大量与状态相关的条件语句(如 if-else 或 switch-case)
  • 状态切换频繁,且状态行为复杂

常见例子:

  • 工作流引擎(如订单状态:待支付、已支付、已发货、已完成等)
  • TCP 连接状态(CLOSED、LISTEN、SYN_SENT、ESTABLISHED 等)
  • 游戏角色状态(待机、攻击、防御、死亡等)

三、状态模式的结构

  • Context(环境类):持有当前状态对象,负责状态切换
  • State(抽象状态):定义所有具体状态的公共接口
  • ConcreteState(具体状态):实现具体状态对应的行为

四、UML 类图

+----------------+        +---------------------+
|    Context     |<>----->|     State           |
+----------------+        +---------------------+
| state: State   |        | + handle()          |
| + setState()   |        +---------------------+
| + request()    |                /_\
+----------------+                 |
                                   |
                +------------------+------------------+
                |                                     |
      +---------------------+             +---------------------+
      | ConcreteStateA      |             | ConcreteStateB      |
      +---------------------+             +---------------------+
      | + handle()          |             | + handle()          |
      +---------------------+             +---------------------+

五、Java 实现代码示例

1. 抽象状态接口

public interface State {
    void handle(Context context);
}

2. 具体状态类

public class StateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态:A,切换到状态B");
        context.setState(new StateB());
    }
}

public class StateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态:B,切换到状态A");
        context.setState(new StateA());
    }
}

3. 环境类

public class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

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

    public void request() {
        state.handle(this);
    }
}

4. 客户端调用

public class Main {
    public static void main(String[] args) {
        Context context = new Context(new StateA());
        context.request(); // 输出:当前状态:A,切换到状态B
        context.request(); // 输出:当前状态:B,切换到状态A
        context.request(); // 输出:当前状态:A,切换到状态B
    }
}

六、实际应用案例:订单状态流转

以电商订单为例,订单有“待支付”、“已支付”、“已发货”、“已完成”四种状态,每种状态下允许的操作不同。

1. 状态接口

public interface OrderState {
    void next(OrderContext ctx);
    void prev(OrderContext ctx);
    String getStatus();
}

2. 具体状态类

public class PendingState implements OrderState {
    public void next(OrderContext ctx) {
        ctx.setState(new PaidState());
    }
    public void prev(OrderContext ctx) {
        System.out.println("已是初始状态,不能回退");
    }
    public String getStatus() {
        return "待支付";
    }
}

public class PaidState implements OrderState {
    public void next(OrderContext ctx) {
        ctx.setState(new ShippedState());
    }
    public void prev(OrderContext ctx) {
        ctx.setState(new PendingState());
    }
    public String getStatus() {
        return "已支付";
    }
}

public class ShippedState implements OrderState {
    public void next(OrderContext ctx) {
        ctx.setState(new CompletedState());
    }
    public void prev(OrderContext ctx) {
        ctx.setState(new PaidState());
    }
    public String getStatus() {
        return "已发货";
    }
}

public class CompletedState implements OrderState {
    public void next(OrderContext ctx) {
        System.out.println("订单已完成,不能再前进");
    }
    public void prev(OrderContext ctx) {
        ctx.setState(new ShippedState());
    }
    public String getStatus() {
        return "已完成";
    }
}

3. 环境类

public class OrderContext {
    private OrderState state;

    public OrderContext() {
        state = new PendingState();
    }

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

    public void next() {
        state.next(this);
    }

    public void prev() {
        state.prev(this);
    }

    public void printStatus() {
        System.out.println("当前订单状态:" + state.getStatus());
    }
}

4. 客户端调用

public class Main {
    public static void main(String[] args) {
        OrderContext order = new OrderContext();
        order.printStatus(); // 待支付
        order.next();
        order.printStatus(); // 已支付
        order.next();
        order.printStatus(); // 已发货
        order.next();
        order.printStatus(); // 已完成
        order.next();        // 订单已完成,不能再前进
        order.prev();
        order.printStatus(); // 已发货
    }
}

七、状态模式的优缺点

优点:

  • 状态切换逻辑清晰,易于扩展和维护
  • 避免大量 if-else 或 switch-case
  • 状态行为封装,符合开闭原则

缺点:

  • 状态类数量可能增多
  • 结构相对复杂

八、总结

状态模式是处理对象状态切换和行为变化的经典方案,广泛应用于工作流、状态机、游戏开发等场景。掌握状态模式有助于编写灵活、可扩展的代码结构。

建议:

  • 当对象行为依赖于状态且状态切换复杂时,优先考虑状态模式
  • 状态模式与策略模式、命令模式等常结合使用

如需更多设计模式讲解或源码分析,欢迎留言交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Socket 编程 UDP

目录 1. UDP网络编程 1.1 echo server 1.1.1 接口 1.1.1.1 创建套接字 1.1.1.2 绑定 1.1.1.3 bzero 1.1.1.4 htons&#xff08;主机序列转网络序列&#xff09; 1.1.1.5 inet_addr&#xff08;主机序列IP转网络序列IP&#xff09; 1.1.1.6 recvfrom&#xff08;让服务…

Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本

Jenkins实践(8):服务器A通过SSH调用服务器B执行Python自动化脚本 1、需求: 1、Jenkins服务器在74上,Python脚本在196服务器上 2、需要在服务器74的Jenkins上调用196上的脚本执行Python自动化测试 2、操作步骤 第一步:Linux Centos7配置SSH免密登录 Linux Centos7配置S…

lua的注意事项2

总之&#xff0c;下面的返回值不是10&#xff0c;a&#xff0c;b 而且

前端八股之HTML

前端秘籍-HTML篇 1. src和href的区别 src 用于替换当前元素&#xff0c;href 用于在当前文档和引用资源之间确立联系。 &#xff08;1&#xff09;src src 是 source 的缩写&#xff0c;指向外部资源的位置&#xff0c;指向的内容将会嵌入到文档中当前标签所在位置&#xff1…

鲲鹏Arm+麒麟V10,国产化信创 K8s 离线部署保姆级教程

Rainbond V6 国产化部署教程&#xff0c;针对鲲鹏 CPU 麒麟 V10 的离线环境&#xff0c;手把手教你从环境准备到应用上线&#xff0c;所有依赖包提前打包好&#xff0c;步骤写成傻瓜式操作指南。别说技术团队了&#xff0c;照着文档一步步来&#xff0c;让你领导来都能独立完成…

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本章将开启Qt的学习&#xff0c;Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位&#xff0c;因为它适合嵌入式和多种平台而被广泛使用…

IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)

文章目录 概述产品和设备实例的产品和设备产品和设备的关联单个产品有多个设备为产品创建多个设备产品模型和物模型设备影子&#xff08;远程代理&#xff09; 新建产品模型定义编解码插件开发编解码插件工作原理消息类型与二进制码流添加消息&#xff08;数据上报消息&#xf…

Replacing iptables with eBPF in Kubernetes with Cilium

source: https://archive.fosdem.org/2020/schedule/event/replacing_iptables_with_ebpf/attachments/slides/3622/export/events/attachments/replacing_iptables_with_ebpf/slides/3622/Cilium_FOSDEM_2020.pdf 使用Cilium&#xff0c;结合eBPF、Envoy、Istio和Hubble等技术…

数学建模之最短路径问题

1 问题的提出 这个是我们的所要写的题目&#xff0c;我们要用LINGO编程进行编写这个题目&#xff0c;那么就是需要进行思考这个怎么进行构建这个问题的模型 首先起点&#xff0c;中间点&#xff0c;终点我们要对这个进行设计 2 三个点的设计 起点的设计 起点就是我们进去&am…

测试概念 和 bug

一 敏捷模型 在面对在开发项目时会遇到客户变更需求以及合并新的需求带来的高成本和时间 出现的敏捷模型 敏捷宣言 个人与交互重于过程与工具 强调有效的沟通 可用的软件重于完备的文档 强调轻文档重产出 客户协作重于合同谈判 主动及时了解当下的要求 相应变化…

zynq 级联多个ssd方案设计(ECAM BUG修改)

本文讲解采用zynq7045芯片如何实现200T容量高速存储方案设计&#xff0c;对于大容量高速存储卡&#xff0c;首先会想到采用pcie switch级联方式&#xff0c;因为单张ssd的容量是有限制的&#xff08;目前常见的m.2接口容量为4TB&#xff0c;U.2接口容量为16TB&#xff09;&…

brep2seq 论文笔记

Brep2Seq: a dataset and hierarchical deep learning network for reconstruction and generation of computer-aided design models | Journal of Computational Design and Engineering | Oxford Academic 这段文本描述了一个多头自注意力机制&#xff08;MultiHead Attenti…

【运维实战】Linux 中设置 sudo ,8个有用的 sudoers 配置!

在Linux及其他类Unix操作系统中&#xff0c;只有 root 用户能够执行所有命令并进行关键系统操作&#xff0c;例如安装更新软件包、删除程序、创建用户与用户组、修改重要系统配置文件等。 但担任 root 角色的系统管理员可通过配置sudo命令&#xff0c;允许普通系统用户执行特定…

江科大SPI串行外设接口hal库实现

hal库相关函数 初始化结构体 typedef struct {uint32_t Mode; /*SPI模式*/uint32_t Direction; /*SPI方向*/uint32_t DataSize; /*数据大小*/uint32_t CLKPolarity; /*时钟默认极性控制CPOL*/uint32_t CLKPhase; /*…

[网页五子棋][对战模块]前后端交互接口(建立连接、连接响应、落子请求/响应),客户端开发(实现棋盘/棋子绘制)

文章目录 约定前后端交互接口建立连接建立连接响应针对"落子"的请求和响应 客户端开发实现棋盘/棋子绘制部分逻辑解释 约定前后端交互接口 对战模块和匹配模块使用的是两套逻辑&#xff0c;使用不同的 websocket 的路径进行处理&#xff0c;做到更好的耦合 建立连接 …

【ArcGIS Pro微课1000例】0071:将无人机照片生成航线、轨迹点、坐标高程、方位角

文章目录 一、照片预览二、生成轨迹点三、照片信息四、查看方位角五、轨迹点连成线一、照片预览 数据位于配套实验数据包中的0071.rar,解压之后如下: 二、生成轨迹点 地理标记照片转点 (数据管理),用于根据存储在地理标记照片文件(.jpg 或 .tif)元数据中的 x、y 和 z 坐…

Ubuntu Zabbix 钉钉报警

文章目录 概要Zabbix警监控脚本技术细节配置zabbix告警 概要 提示&#xff1a;本教程用于Ubuntu &#xff0c;zabbix7.0 Zabbix警监控脚本 提示&#xff1a;需要创建一个脚本 #检查是否有 python3 和版本 rootzabbix:~# python3 --version Python 3.12.3在/usr/lib/zabbix/…

threejs顶点UV坐标、纹理贴图

1. 创建纹理贴图 通过纹理贴图加载器TextureLoader的load()方法加载一张图片可以返回一个纹理对象Texture&#xff0c;纹理对象Texture可以作为模型材质颜色贴图.map属性的值。 const geometry new THREE.PlaneGeometry(200, 100); //纹理贴图加载器TextureLoader const te…

STM32 RTC实时时钟\BKP备份寄存器\时间戳

一、Unix时间戳 想要计算当地北京时间&#xff0c;需要根据经度和闰年之类的运算得到(c语言里面可以调用time.h的函数) 二、UTC/GMT&#xff08;科普&#xff09; 三、时间戳转化 C语言的time.h模块提供了时间获取和时间戳转换的相关函数&#xff0c;可以方便的进行秒计数器、…

Axure设计案例——科技感立体柱状图

想让你的数据展示告别平淡无奇&#xff0c;成为吸引全场目光的焦点吗&#xff1f;快来瞧瞧这个Axure设计的科技感立体柱状图案例&#xff01;科技感设计风格借助逼真的立体效果打破传统柱状图的平面感&#xff0c;营造出一种令人眼前一亮的视觉震撼。每一个柱状体都仿佛是真实存…