当前位置: 首页 > news >正文

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

文章目录

  • 简介
  • 状态模式基础
    • 定义状态接口或抽象类
      • 实现具体状态类
  • 上下文类与状态转换
    • 上下文类的定义和作用
    • 状态转换及触发条件
  • 状态模式的优势与适用性
    • 优点一:可维护的代码
    • 优点二:清晰的状态管理
    • 适用场景一:对象拥有多个状态
    • 适用场景二:状态转换频繁且复杂
  • 具体业务场景应用:电商订单状态切换
  • 状态模式与其他设计模式的结合
    • 策略模式与状态模式的对比与联系
    • 工厂模式与状态模式的结合实践
  • 总结

简介

  • 状态模式是一种行为型设计模式,用于处理对象在不同状态下的行为变化。它将对象的行为封装在不同状态类中,通过状态的切换实现不同行为的触发。
  • 本文将介绍状态模式的基本概念、应用场景以及优势与适用性。
    在这里插入图片描述

状态模式基础

定义状态接口或抽象类

public abstract class State{public abstract void WriteProgram(Work w);}

实现具体状态类

    //上午工作状态public class ForenoonState : State{public override void WriteProgram(Work w){
//这里的判断就是决定要用那种行为展现出来,如果 不符合当前状态,那么就去到已经设置好的下一个具体状态类中进行相同的操作。if (w.hour < 12){Console.WriteLine("当前时间:{0}点 上午工作,精神百倍",w.Hour);}else{w.SetState(new NoonState());w.WriteProgram();}}}//中午工作状态public class NoonState : State{public override void WriteProgram(Work w){if (w.hour < 13){Console.WriteLine("当前时间:{0}点 饿了,想吃饭;犯困,想睡觉。", w.Hour);}else{w.SetState(new AfternoonState()); w.WriteProgram();}}}//下午工作状态public class AfternoonState : State{public override void WriteProgram(Work w){if (w.hour < 17){Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour);}else{w.SetState(new EveningState()); w.WriteProgram();}}}//晚上工作状态public class EveningState : State{public override void WriteProgram(Work w){if (w.finish ){w.SetState(new RestState());w.WriteProgram();//完成任务就转成下班状态}else{if (w.hour <21){Console.WriteLine("当前时间:{0}点 加班了,加班人累啊", w.Hour);}else {w.SetState(new SleepingState()); w.WriteProgram();//超过21点,转入睡眠状态}}}}//睡眠状态public class SleepingState:State{public override void WriteProgram(Work w){Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);}}//下班休息状态public class RestState : State{public override void WriteProgram(Work w){Console.WriteLine("当前时间:{0}点 不行了,睡着了", w.Hour);}}

具体工作类:

    public class Work{public State current;public Work(){current = new ForenoonState();	//初始化为上午9点开始上班}public double hour;//小时钟,状态转换的依据public bool finish = false;//完成任务属性,是否能下班的依据//这个方法主要就是把具体的状态类给进来,然后让下面的方法去使用public void SetState(State s)	//得到状态{current = s;}
//下面这个方法从始至终都没有发生改变,改变是其内部具体的展现值。public void WriteProgram() {current.WriteProgram(this);}}

上下文类与状态转换

上下文类的定义和作用

  • 上下文类包含状态对象的引用,并将具体行为委托给当前状态对象执行。
  • 示例代码:
// 上下文类
public class Context {private State currentState;public void setCurrentState(State state) {this.currentState = state;}public void request() {// 委托当前状态对象执行行为currentState.handle();}
}

状态转换及触发条件

  • 状态转换指从一个状态切换到另一个状态的过程。
  • 触发条件是使状态转换发生的条件。
  • 示例代码:
// 具体状态类A
public class ConcreteStateA implements State {// ...@Overridepublic void handle() {// 具体状态A的行为逻辑// 状态转换及触发条件if (/*触发条件*/) {context.setCurrentState(new ConcreteStateB());}}
}

状态模式的优势与适用性

优点一:可维护的代码

  • 状态模式将每个状态的行为逻辑封装在独立的状态类中,易于理解和维护。

优点二:清晰的状态管理

  • 状态模式通过上下文类进行状态转换和行为委托,使状态管理更加清晰明确。

适用场景一:对象拥有多个状态

  • 当对象具有多个状态且不同状态下表现出不同行为时,可以使用状态模式进行状态管理和行为切换。

适用场景二:状态转换频繁且复杂

  • 当状态转换频繁且存在复杂的触发条件时,状态模式能够提供一种结构化的方式来管理状态转换。

具体业务场景应用:电商订单状态切换


为了演示订单状态管理的状态模式业务代码,我将使用Java语言来实现。以下是一个简单的示例:

首先,我们定义订单状态接口 OrderState,其中包含了处理订单状态的方法 handle()

// 订单状态接口
public interface OrderState {void handle();
}

然后,我们创建具体的订单状态类,包括待支付状态、已支付状态、待发货状态和已发货状态。每个状态类实现了订单状态接口,并根据相应的状态实现了自己的行为逻辑。

// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

接下来,我们创建订单类 Order,它包含了当前订单状态和一些操作方法。

// 订单类
public class Order {private OrderState currentState; // 当前订单状态public Order() {currentState = new PendingPaymentState(); // 默认初始状态为待支付}public void setCurrentState(OrderState state) {currentState = state;}public void request() {currentState.handle();}
}

最后,我们可以进行测试,模拟订单在不同状态下的行为变化:

public class Main {public static void main(String[] args) {Order order = new Order(); // 创建订单// 待支付状态order.request();// 支付订单,状态转换为已支付order.setCurrentState(new PaidState());order.request();// 发货,状态转换为待发货order.setCurrentState(new ToBeShippedState());order.request();// 完成发货,状态转换为已发货order.setCurrentState(new ShippedState());order.request();}
}

运行以上代码,将得到如下输出:
在这里插入图片描述

以上示例演示了订单状态管理的状态模式业务代码。通过状态模式,我们可以根据订单状态的变化触发不同的行为逻辑,并且可以方便地添加新的订单状态,以满足业务需求。

状态模式与其他设计模式的结合

策略模式与状态模式的对比与联系

策略模式和状态模式都属于行为型设计模式,它们都关注对象在不同的情境下具有不同的行为。虽然它们有相似之处,但在设计意图、应用场景和实现方式上存在一些差异。

下面是策略模式和状态模式的对比与联系:

对比:

  1. 设计意图:策略模式旨在通过定义一组算法或策略,并将其封装成独立的对象,使得这些算法可以互换使用。状态模式旨在让一个对象在其内部状态改变时改变其行为,从而实现状态之间的转换。

  2. 关注点:策略模式主要关注算法的选择和封装,使得具体的策略可以独立于客户端进行变化。状态模式主要关注对象的状态的管理和转换,以及不同状态下的行为执行。

  3. 对象角色:策略模式通常包含一个上下文类(Context)和一组策略类(Strategies),客户端与上下文类进行交互。状态模式通常包含一个上下文类(Context)和一组状态类(States),客户端与上下文类进行交互。

联系:

  1. 行为的封装:策略模式和状态模式都将行为封装到独立的对象中,使得行为可以被动态地变化。

  2. 对象之间的互动:策略模式和状态模式都需要一个上下文类(Context)来与策略对象或状态对象进行交互,并将具体的行为委托给策略对象或状态对象来执行。

  3. 可扩展性:策略模式和状态模式都具有较好的可扩展性。在策略模式中,可以方便地新增、修改或切换不同的策略对象。在状态模式中,可以方便地新增、修改或切换不同的状态对象。

总的来说,策略模式和状态模式都是强调对象行为的灵活性和可扩展性的设计模式。它们的主要区别在于策略模式关注算法的选择和封装,而状态模式关注对象状态的管理和转换。根据具体的需求,选择适合的模式来提高代码的可维护性和可扩展性。

工厂模式与状态模式的结合实践

  • 结合工厂模式可以实现状态类的动态创建和切换,增强了状态模式的灵活性和可扩展性。
    结合工厂模式可以实现状态类的动态创建和切换,从而增强了状态模式的灵活性和可扩展性。工厂模式可以将状态对象的创建和状态转换逻辑与客户端代码分离,使得系统更加可维护和可扩展。

下面是一个示例,演示了如何结合工厂模式和状态模式来管理订单的状态:

首先,定义订单状态接口 OrderState 和具体的订单状态类,与之前的示例相同。

// 订单状态接口
public interface OrderState {void handle();
}// 待支付状态类
public class PendingPaymentState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待支付");// 处理待支付状态的逻辑}
}// 已支付状态类
public class PaidState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已支付");// 处理已支付状态的逻辑}
}// 待发货状态类
public class ToBeShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:待发货");// 处理待发货状态的逻辑}
}// 已发货状态类
public class ShippedState implements OrderState {@Overridepublic void handle() {System.out.println("当前订单状态:已发货");// 处理已发货状态的逻辑}
}

然后,创建一个工厂类 OrderStateFactory,用于动态创建订单状态对象。
在严格意义上这个工厂是一个不支持扩充的,但是在这里仅作为一个示例,如果想要真正达到动态创建还是需要用到工厂方法,这里只能算是一个简单工厂。

// 订单状态工厂类  
public class OrderStateFactory {public static OrderState createOrderState(String stateName) {switch (stateName.toLowerCase()) {case "pendingpayment":return new PendingPaymentState();case "paid":return new PaidState();case "tobeshipped":return new ToBeShippedState();case "shipped":return new ShippedState();default:throw new IllegalArgumentException("Invalid state name");}}
}

接下来,我们可以使用上述的状态类和工厂类进行订单状态切换的实践:

public class Main {public static void main(String[] args) {Order order = new Order(); // 创建订单// 设置待支付状态order.setCurrentState(OrderStateFactory.createOrderState("PendingPayment"));order.request();// 支付订单,切换到已支付状态order.setCurrentState(OrderStateFactory.createOrderState("Paid"));order.request();// 发货,切换到待发货状态order.setCurrentState(OrderStateFactory.createOrderState("ToBeShipped"));order.request();// 完成发货,切换到已发货状态order.setCurrentState(OrderStateFactory.createOrderState("Shipped"));order.request();}
}

通过工厂模式,我们可以根据状态名称动态地创建不同的订单状态对象,并将其设置为上下文类的当前状态。这样,如果要新增或修改订单状态,只需要修改工厂类的代码,而不需要修改客户端的代码。这增强了状态模式的灵活性和可扩展性。

总结

  • 状态模式是一种有助于管理对象不同状态下行为变化的设计模式。通过将状态和行为封装在不同状态类中,状态模式提供了一种结构化的方式来处理状态转换和行为委托。它适用于对象拥有多个状态且状态转换复杂的场景,并与其他设计模式如策略模式、工厂模式等相结合能够进一步扩展其功能和灵活性。

相关文章:

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

文章目录 简介状态模式基础定义状态接口或抽象类实现具体状态类 上下文类与状态转换上下文类的定义和作用状态转换及触发条件 状态模式的优势与适用性优点一&#xff1a;可维护的代码优点二&#xff1a;清晰的状态管理适用场景一&#xff1a;对象拥有多个状态适用场景二&#x…...

弹窗、抽屉、页面跳转区别 | web交互入门

当用户点击或触发浏览页面的某个操作&#xff0c;有很多web交互方式&#xff0c;可以大致分为弹窗、抽屉、跳转新页面三种web交互方式。虽然这三种web交互方式看起来没什么不同&#xff0c;但实际上弹窗、抽屉、跳转新页面对交互体验有蛮大的影响。 这需要UI\UX设计师针对不同…...

说说Flink运行模式

分析&回答 1.开发者模式 在idea中运行Flink程序的方式就是开发模式。 2.local-cluster模式 Flink中的Local-cluster(本地集群)模式,单节点运行&#xff0c;主要用于测试, 学习。 3.Standalone模式 独立集群模式&#xff0c;由Flink自身提供计算资源。 4.Yarn模式 把Fl…...

视频汇聚/视频云存储/视频监控管理平台EasyCVR新增首次登录强制修改密码

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚平台既具…...

C语言控制语句——分支语句

条件语句用来根据不同的条件来执行不同的语句&#xff0c;C语言中常用的条件语句包括if语句和switch语句。 if 语句 语法格式&#xff1a; if (条件) {条件成立时&#xff0c;要做的事…… }案例需求&#xff1a; 定义一个整数变量记录年龄判断是否满 18 岁 &#xff08;>…...

音视频 fmpeg命令裁剪和合并视频

一、生成测试文件 找三个不同的视频每个视频截取10秒内容 ffmpeg -i 沙海02.mp4 -ss 00:05:00 -t 10 -codec copy 1.mp4 ffmpeg -i 复仇者联盟3.mp4 -ss 00:05:00 -t 10 -codec copy 2.mp4 ffmpeg -i 红海行动.mp4 -ss 00:05:00 -t 10 -codec copy 3.mp4如果音视频格式不统一…...

机器学习基础17-基于波士顿房价(Boston House Price)数据集训练模型的整个过程讲解

机器学习是一项经验技能&#xff0c;实践是掌握机器学习、提高利用机器学习 解决问题的能力的有效方法之一。那么如何通过机器学习来解决问题呢&#xff1f; 本节将通过一个实例来一步一步地介绍一个回归问题。 本章主要介绍以下内容&#xff1a; 如何端到端地完成一个回归问题…...

哈希的应用——布隆过滤器

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;数据结构——位图 ☂️<3>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<4>前言&#xff1a;布隆过滤器是由布隆&#xff08;Burton Howard Bloom&…...

LNMT的多机部署和双机热备

目录 一、环境 二、配置tomcat 三、配置nfs共享 四、配置nginx 1、两台都需要折磨配置 2、在http下面插入这两条信息 五、配置keepalived 1、安装 2、重新启动一下keepalived查看IP 六、验证双机热备 1、查看调度器备的IP&#xff0c;ip漂移说明keepalived生效 2、访…...

软件测试/测试开发丨Pytest和Allure报告 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/26755 Pytest 命名规则 类型规则文件test_开头 或者 _test 结尾类Test 开头方法/函数test_开头注意&#xff1a;测试类中不可以添加__init__构造函数 注…...

十七、命令模式

一、什么是命令模式 命令&#xff08;Command&#xff09;模式的定义&#xff1a;将一个请求封装为一个对象&#xff0c;使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通&#xff0c;这样方便将命令对象进行储存、传递、调用、增加与管理。   命令…...

服务器安装 anaconda 及 conda: command not found [解决方案]

[解决方案] conda: command not found Anaconda3 安装conda: command not found Anaconda3 安装 由于连接的服务器&#xff0c;无法直接在anaconda官网上下载安装文件&#xff0c;所以使用如下方法&#xff1a; wget https://repo.anaconda.com/archive/Anaconda3-2023.03-Li…...

自动驾驶和辅助驾驶系统的概念性架构(二)

摘要&#xff1a; 本篇为第二部分主要介绍底层计算单元、示例工作负载 前言 本文档参考自动驾驶计算联盟(Autonomous Vehicle Computing Consortium)关于自动驾驶和辅助驾驶计算系统的概念系统架构。该架构旨在与SAE L1-L5级别的自动驾驶保持一致。本文主要介绍包括功能模块图…...

【c++】VC编译出的版本,发布版本如何使用

目录 使用release类型进行发布 应用程序无法正常启动 0xc000007b 版本对应 vcruntime140d 应用版本 参考文章 使用release类型进行发布 应用程序无法正常启动 0xc000007b "应用程序无法正常启动 0xc000007b" 错误通常是一个 Windows 应用程序错误&#xf…...

自然语言处理(五):子词嵌入(fastText模型)

子词嵌入 在英语中&#xff0c;“helps”“helped”和“helping”等单词都是同一个词“help”的变形形式。“dog”和“dogs”之间的关系与“cat”和“cats”之间的关系相同&#xff0c;“boy”和“boyfriend”之间的关系与“girl”和“girlfriend”之间的关系相同。在法语和西…...

Zabbix“专家坐诊”第202期问答汇总

问题一 Q&#xff1a;请问一下 zabbix 里面怎么能创建出和sh文件有关联的监控项&#xff1f; A&#xff1a; 1.使用 Zabbix Agent 主动模式&#xff1a;如果你在目标主机上安装了 Zabbix Agent&#xff0c;并且想要监控与 sh 文件相关的指标&#xff0c;可以创建一个自定义的…...

【c语言】输出n行按如下规律排列的数

题述&#xff1a;输出n行按如下规律排列的数 输入&#xff1a; 4(应该指的是n) 输出: 思路&#xff1a; 利用下标的规律求解&#xff0c;考察数组下标的灵活应用&#xff0c;我们可以看出数从1开始是斜着往下放的&#xff0c;那么我们如何利用两层for循环求解这道题&#xff…...

023 - STM32学习笔记 - 扩展外部SDRAM(二) - 扩展外部SDRAM实验

023- STM32学习笔记 - 扩展外部SDRAM&#xff08;一&#xff09; - 扩展外部SDRAM实验 本节内容中要配置的引脚很多&#xff0c;如果你用的开发板跟我的不一样&#xff0c;请详细参照STM32规格书中说明对相关GPIO引脚进行配置。 先提前对本届内容的变成步骤进行总结如下&…...

机器学习 | Python实现XGBoost极限梯度提升树模型答疑

机器学习 | MATLAB实现XGBoost极限梯度提升树模型答疑 目录 机器学习 | MATLAB实现XGBoost极限梯度提升树模型答疑问题系列问题回答问题系列 关于XGBoost有几个问题想请教一下。1.XGBoost的API有哪些种调用方法?2.参数如何调? 问题回答 XGBoost的API有2种调用方法,一种是我们…...

关于使用远程工具连接mysql数据库时,提示:Public Key Retrieval is not allowed

我在使用DBeaver工具连接 数据库时&#xff0c;提示&#xff1a;Public Key Retrieval is not allowed&#xff0c; 我在前一天还是可以连接的&#xff0c;但是今天突然无法连接了&#xff0c; 但是最后捣鼓了一下又可以了。 具体方法&#xff1a;首先先把mysql服务停了&#x…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...