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

[go] 状态模式

状态模式

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

模型说明

  • 上下文 (Context) 保存了对于一个具体状态对象的引用, 并会将所有与该状态相关的工作委派给它。 上下文通过状态接口与状态对象交互, 且会提供一个设置器用于传递新的状态对象。

  • 状态 (State) 接口会声明特定于状态的方法。 这些方法应能被其他所有具体状态所理解, 因为你不希望某些状态所拥有的方法永远不会被调用。

  • 具体状态 (Concrete States) 会自行实现特定于状态的方法。 为了避免多个状态中包含相似代码, 你可以提供一个封装有部分通用行为的中间抽象类。

  • 状态对象可存储对于上下文对象的反向引用。 状态可以通过该引用从上下文处获取所需信息, 并且能触发状态转移。

  • 上下文和具体状态都可以设置上下文的下个状态, 并可通过替换连接到上下文的状态对象来完成实际的状态转换。

优缺点

1.优点

  • 单一职责原则: 将与特定状态相关的代码放在单独的类中。
  • 开闭原则: 无需修改已有状态类和上下文就能引入新状态。
  • 通过消除臃肿的状态机条件语句简化上下文代码。

2.缺点

  • 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。

使用场景

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

参考代码
一台自动售货机上使用状态设计模式:

  • 有商品 (has­Item)
  • 无商品 (no­Item)
  • 商品已请求 (item­Requested)
  • 收到纸币 (has­Money)

同时, 自动售货机也会有不同的操作。 再一次的, 为了简单起见, 我们假设其只会执行 4 种操作:

  • 选择商品
  • 添加商品
  • 插入纸币
  • 提供商品
// vendingMachine.go 自动售货机
package mainimport "fmt"type VendingMachine struct {hasItem       StateitemRequested StatehasMoney      StatenoItem        StatecurrentState StateitemCount intitemPrice int
}func newVendingMachine(itemCount, itemPrice int) *VendingMachine {v := &VendingMachine{itemCount: itemCount,itemPrice: itemPrice,}hasItemState := &HasItemState{vendingMachine: v,}itemRequestedState := &ItemRequestedState{vendingMachine: v,}hasMoneyState := &HasMoneyState{vendingMachine: v,}noItemState := &NoItemState{vendingMachine: v,}v.setState(hasItemState)v.hasItem = hasItemStatev.itemRequested = itemRequestedStatev.hasMoney = hasMoneyStatev.noItem = noItemStatereturn v
}func (v *VendingMachine) requestItem() error {return v.currentState.requestItem()
}func (v *VendingMachine) addItem(count int) error {return v.currentState.addItem(count)
}func (v *VendingMachine) insertMoney(money int) error {return v.currentState.insertMoney(money)
}func (v *VendingMachine) dispenseItem() error {return v.currentState.dispenseItem()
}func (v *VendingMachine) setState(s State) {v.currentState = s
}func (v *VendingMachine) incrementItemCount(count int) {fmt.Printf("Adding %d items\n", count)v.itemCount = v.itemCount + count
}
// state.go 状态接口
package maintype State interface {addItem(int) errorrequestItem() errorinsertMoney(money int) errordispenseItem() error
}
// noItemState.go 无商品状态
package mainimport "fmt"type NoItemState struct {vendingMachine *VendingMachine
}func (i *NoItemState) requestItem() error {return fmt.Errorf("Item out of stock")
}func (i *NoItemState) addItem(count int) error {i.vendingMachine.incrementItemCount(count)i.vendingMachine.setState(i.vendingMachine.hasItem)return nil
}func (i *NoItemState) insertMoney(money int) error {return fmt.Errorf("Item out of stock")
}
func (i *NoItemState) dispenseItem() error {return fmt.Errorf("Item out of stock")
}
// hasItemState.go 有商品状态
package mainimport "fmt"type HasItemState struct {vendingMachine *VendingMachine
}func (i *HasItemState) requestItem() error {if i.vendingMachine.itemCount == 0 {i.vendingMachine.setState(i.vendingMachine.noItem)return fmt.Errorf("No item present")}fmt.Printf("Item requestd\n")i.vendingMachine.setState(i.vendingMachine.itemRequested)return nil
}func (i *HasItemState) addItem(count int) error {fmt.Printf("%d items added\n", count)i.vendingMachine.incrementItemCount(count)return nil
}func (i *HasItemState) insertMoney(money int) error {return fmt.Errorf("Please select item first")
}
func (i *HasItemState) dispenseItem() error {return fmt.Errorf("Please select item first")
}
// itemRequestedState.go 请求商品
package mainimport "fmt"type ItemRequestedState struct {vendingMachine *VendingMachine
}func (i *ItemRequestedState) requestItem() error {return fmt.Errorf("Item already requested")
}func (i *ItemRequestedState) addItem(count int) error {return fmt.Errorf("Item Dispense in progress")
}func (i *ItemRequestedState) insertMoney(money int) error {if money < i.vendingMachine.itemPrice {return fmt.Errorf("Inserted money is less. Please insert %d", i.vendingMachine.itemPrice)}fmt.Println("Money entered is ok")i.vendingMachine.setState(i.vendingMachine.hasMoney)return nil
}
func (i *ItemRequestedState) dispenseItem() error {return fmt.Errorf("Please insert money first")
}
// hasMoneyState.go 收到钱
package mainimport "fmt"type HasMoneyState struct {vendingMachine *VendingMachine
}func (i *HasMoneyState) requestItem() error {return fmt.Errorf("Item dispense in progress")
}func (i *HasMoneyState) addItem(count int) error {return fmt.Errorf("Item dispense in progress")
}func (i *HasMoneyState) insertMoney(money int) error {return fmt.Errorf("Item out of stock")
}
func (i *HasMoneyState) dispenseItem() error {fmt.Println("Dispensing Item")i.vendingMachine.itemCount = i.vendingMachine.itemCount - 1if i.vendingMachine.itemCount == 0 {i.vendingMachine.setState(i.vendingMachine.noItem)} else {i.vendingMachine.setState(i.vendingMachine.hasItem)}return nil
}
// main.go 客户端
package mainimport ("fmt""log"
)func main() {vendingMachine := newVendingMachine(1, 10)err := vendingMachine.requestItem()if err != nil {log.Fatalf(err.Error())}err = vendingMachine.insertMoney(10)if err != nil {log.Fatalf(err.Error())}err = vendingMachine.dispenseItem()if err != nil {log.Fatalf(err.Error())}fmt.Println()err = vendingMachine.addItem(2)if err != nil {log.Fatalf(err.Error())}fmt.Println()err = vendingMachine.requestItem()if err != nil {log.Fatalf(err.Error())}err = vendingMachine.insertMoney(10)if err != nil {log.Fatalf(err.Error())}err = vendingMachine.dispenseItem()if err != nil {log.Fatalf(err.Error())}
}

output:

Item requestd
Money entered is ok
Dispensing ItemAdding 2 itemsItem requestd
Money entered is ok
Dispensing Item

相关文章:

[go] 状态模式

状态模式 允许对象在内部状态改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。 模型说明 上下文 &#xff08;Context&#xff09; 保存了对于一个具体状态对象的引用&#xff0c; 并会将所有与该状态相关的工作委派给它。 上下文通过状态接口与状态对象交互&…...

uniapp沉浸式导航栏+自定义导航栏组件

在 UniApp 中实现沉浸式导航栏并结合自定义导航栏组件 一、沉浸式导航栏设置 在pages.json中配置页面样式 在需要设置沉浸式导航栏的页面的style选项中进行如下配置&#xff1a; {"pages": [{"path": "pages/pageName/pageName","style&qu…...

光伏仿真:排布设计如何优化用户体验?

1、屋顶绘制精准 光伏系统的性能直接受到屋顶结构的影响&#xff0c;因此&#xff0c;屋顶绘制的精准性是光伏仿真设计的首要任务。现代光伏仿真软件通过直观的界面和强大的图形编辑功能&#xff0c;使得用户能够轻松导入或绘制出待安装光伏系统的屋顶形状。无论是平面屋顶、斜…...

Vue使用axios二次封装、解决跨域问题

1、什么是 axios 在实际开发过程中&#xff0c;浏览器通常需要和服务器端进行数据交互。而 Vue.js 并未提供与服务器端通信的接口。从 Vue.js 2.0 版本之后&#xff0c;官方推荐使用 axios 来实现 Ajax 请求。axios 是一个基于 promise 的 HTTP 客户端。 关于 promise 的详细介…...

鸿萌数据恢复:如何降低 RAM 故障风险,以避免数据丢失?

天津鸿萌科贸发展有限公司从事数据安全服务二十余年&#xff0c;致力于为各领域客户提供专业的数据恢复、数据备份解决方案与服务&#xff0c;并针对企业面临的数据安全风险&#xff0c;提供专业的相关数据安全培训。 RAM 可能因多种原因而发生故障&#xff0c;并将设备和数据置…...

使用java实现ffmpeg的各种操作

以实现如下功能 1、支持音频文件转mp3&#xff1b;2、支持视频文件转mp4&#xff1b;3、支持视频提取音频&#xff1b;4、支持视频中提取缩略图&#xff1b;5、支持按时长拆分音频文件&#xff1b; 1、工具类 由于部分原因&#xff0c;没有将FfmpegUtil中的静态的命令行与Ty…...

【ArcGIS微课1000例】0122:经纬网、方里网、参考格网绘制案例教程

文章目录 一、ArcGIS格网类型二、绘制经纬网三、绘制方里网四、绘制参考格网五、注意事项一、ArcGIS格网类型 在ArcMap中,可以创建三种类型的格网: 经纬网——将地图分割为经线和纬线。经纬网是用来标识准确地理位置的方式,由经线和纬线构成,相对于经纬线,分别有的经度和…...

电路板上电子元件检测系统源码分享

电路板上电子元件检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comp…...

综合体第三题(DHCP报文分析)

DHCP工作流程&#xff08;一般情况下&#xff09; 例二&#xff08;无忧/22&#xff09; 下图为DHCP客户机获取IP地址等配置信息时&#xff0c;使用Wareshark软件捕获报文中编号为2〜5的4条报文&#xff0c;图中对编号为3的报文进行了解析。分析图中的信息并补全图中①〜⑤处的…...

企业级-pdf预览-前后端

作者&#xff1a;fyupeng 技术专栏&#xff1a;☞ https://github.com/fyupeng 项目地址&#xff1a;☞ https://github.com/fyupeng/distributed-blog-system-api 留给读者 本文 一、介绍 对于PDF预览&#xff0c;有很多开发者都遇到过头疼的难题&#xff0c;今天给大家介绍…...

为什么 qt 成为 c++ 界面编程的第一选择?

一、前言 为什么现在QT越来越成为界面编程的第一选择&#xff0c;笔者从事qt界面编程已经有接近8年&#xff0c;在这之前我做C界面都是基于MFC&#xff0c;也做过5年左右。当时为什么会从MFC转到QT&#xff0c;主要原因是MFC开发界面想做得好看一些十分困难&#xff0c;引用第…...

Day1-顺序表

1. 数据结构-基本概念 数据之间的相互关系&#xff0c;包括三种关系&#xff1a;逻辑结构&#xff1a;表示数据元素之间的抽象关系(如邻接关系、从属关系等)。有四种基本的逻辑结构&#xff1a;集合结构、线性结构、树形结构、图状结构存储结构&#xff1a;数据的逻辑结构在计算…...

PostgreSQL - pgvector 插件构建向量数据库并进行相似度查询

在现代的机器学习和人工智能应用中&#xff0c;向量相似度检索是一个非常重要的技术&#xff0c;尤其是在文本、图像或其他类型的嵌入向量的操作中。本文将介绍如何在 PostgreSQL 中安装 pgvector 插件&#xff0c;用于存储和检索向量数据&#xff0c;并展示如何通过 Python 脚…...

UR机器人坐标系转化

UR机器人读取上来的坐标系是旋转矢量&#xff0c;每次都要查一下怎么转换&#xff0c;在这里记录以下...

【每日一题】LeetCode 2306.公司命名(位运算、数组、哈希表、字符串、枚举)

【每日一题】LeetCode 2306.公司命名&#xff08;位运算、数组、哈希表、字符串、枚举&#xff09; 题目描述 给定一个字符串数组 ideas&#xff0c;表示在公司命名过程中使用的名字列表。我们需要从 ideas 中选择两个不同的名字&#xff0c;称为 ideaA 和 ideaB。然后交换 i…...

240922-chromadb的基本使用

A. 背景介绍 ChromaDB 是一个较新的开源向量数据库&#xff0c;专为高效的嵌入存储和检索而设计。与其他向量数据库相比&#xff0c;ChromaDB 更加专注于轻量化、简单性和与机器学习模型的无缝集成。它的核心目标是帮助开发者轻松管理和使用高维嵌入向量&#xff0c;特别是与生…...

工厂模式和抽象工厂模式的实验报告

1. 实验结果&#xff1a; 记录并附上不同模型对象&#xff08;例如&#xff1a;士兵、机器人、骑士&#xff09;的展示效果截图。 2. 性能分析&#xff1a; 记录并比较抽象工厂模式与直接实例化的性能测试结果&#xff0c;分析它们在不同数量级对象创建时的开销与效益。 2.1…...

C标准库<string.h>-str、strn开头的函数

char *strcat(char *dest, const char *src) 函数功能 strcat 函数用于将一个字符串追加到另一个字符串的尾部。 参数解释 dest&#xff1a;指向目标字符串的指针&#xff0c;这个字符串的尾部将被追加 src 字符串的内容。src&#xff1a;指向源字符串的指针&#xff0c;其…...

Anaconda/Miniconda的删除和安装

要在 MacBook 上删除 Anaconda 或 Miniconda,并重新安装它,您可以按照以下步骤进行操作。 删除 Anaconda/Miniconda 1. 删除 Anaconda/Miniconda 文件和目录 打开 终端 并运行以下命令来删除安装目录。 对于 Anaconda,通常安装在 ~/anaconda3: rm -rf ~/anaconda3对于…...

【Harmony】轮播图特效,持续更新中。。。。

效果预览 swiper官网例子 Swiper 高度可变化 两边等长露出&#xff0c;跟随手指滑动 Swiper 指示器导航点位于 Swiper 下方 卡片楼层层叠一 一、官网 例子 参考代码&#xff1a; // xxx.ets class MyDataSource implements IDataSource {private list: number[] []cons…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...