元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
设计原则
单一职责原则
开闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则
▶
创建型模式
工厂方法模式
抽象工厂
单例模式
建造者模式
原型模式
▶
结构型模式
适配器模式
装饰器模式
代理模式
外观模式
组合模式
桥接模式
享元模式
▶
行为型模式
策略模式
观察者模式
命令模式
模板方法模式
状态模式
责任链模式
迭代器模式
中介者模式
访问者模式
备忘录模式
解释器模式
发布时间:
2025-03-21 15:22
↑
☰
# 状态模式 ## 概述 状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。这种模式将状态封装成独立的类,并将动作委托到代表当前状态的对象。 ## 问题场景 在软件开发中,我们经常会遇到以下场景: 1. 对象的行为依赖于它的状态 2. 代码中包含大量与对象状态有关的条件语句 3. 需要在运行时根据状态改变对象的行为 ## 解决方案 状态模式通过以下方式解决这些问题: ```mermaid classDiagram class Context { -state: State +setState(State) +request() } class State { <<interface>> +handle() } class ConcreteStateA { +handle() } class ConcreteStateB { +handle() } Context o-- State State <|.. ConcreteStateA State <|.. ConcreteStateB ``` 主要角色: 1. 上下文(Context): 定义客户感兴趣的接口,维护一个State子类的实例 2. 状态(State): 定义一个接口以封装与Context的一个特定状态相关的行为 3. 具体状态(ConcreteState): 实现一个与Context某个状态相关的行为 ## 代码示例 ### 1. 基本实现 ```go // State 状态接口 type State interface { Handle() string } // Context 上下文 type Context struct { state State } func NewContext(state State) *Context { return &Context{state: state} } func (c *Context) SetState(state State) { c.state = state } func (c *Context) Request() string { return c.state.Handle() } // ConcreteStateA 具体状态A type ConcreteStateA struct{} func (s *ConcreteStateA) Handle() string { return "State A handling request" } // ConcreteStateB 具体状态B type ConcreteStateB struct{} func (s *ConcreteStateB) Handle() string { return "State B handling request" } ``` ### 2. 实际应用示例 ```go // 以自动售货机为例 // VendingMachineState 售货机状态接口 type VendingMachineState interface { InsertCoin() string EjectCoin() string SelectProduct() string Dispense() string } // VendingMachine 售货机 type VendingMachine struct { noCoinState State hasCoinState State soldState State soldOutState State currentState State count int } func NewVendingMachine(count int) *VendingMachine { v := &VendingMachine{ count: count, } v.noCoinState = &NoCoinState{machine: v} v.hasCoinState = &HasCoinState{machine: v} v.soldState = &SoldState{machine: v} v.soldOutState = &SoldOutState{machine: v} if count > 0 { v.currentState = v.noCoinState } else { v.currentState = v.soldOutState } return v } func (v *VendingMachine) InsertCoin() string { return v.currentState.InsertCoin() } func (v *VendingMachine) EjectCoin() string { return v.currentState.EjectCoin() } func (v *VendingMachine) SelectProduct() string { return v.currentState.SelectProduct() } func (v *VendingMachine) Dispense() string { result := v.currentState.Dispense() if v.count > 0 { v.count-- } return result } func (v *VendingMachine) SetState(state State) { v.currentState = state } // NoCoinState 无硬币状态 type NoCoinState struct { machine *VendingMachine } func (s *NoCoinState) InsertCoin() string { s.machine.SetState(s.machine.hasCoinState) return "You inserted a coin" } func (s *NoCoinState) EjectCoin() string { return "You haven't inserted a coin" } func (s *NoCoinState) SelectProduct() string { return "You need to insert a coin first" } func (s *NoCoinState) Dispense() string { return "You need to insert a coin first" } // HasCoinState 有硬币状态 type HasCoinState struct { machine *VendingMachine } func (s *HasCoinState) InsertCoin() string { return "You can't insert another coin" } func (s *HasCoinState) EjectCoin() string { s.machine.SetState(s.machine.noCoinState) return "Coin returned" } func (s *HasCoinState) SelectProduct() string { s.machine.SetState(s.machine.soldState) return "Product selected" } func (s *HasCoinState) Dispense() string { return "No product dispensed" } // SoldState 售出状态 type SoldState struct { machine *VendingMachine } func (s *SoldState) InsertCoin() string { return "Please wait, we're already giving you a product" } func (s *SoldState) EjectCoin() string { return "Sorry, you already selected a product" } func (s *SoldState) SelectProduct() string { return "Please wait, we're already giving you a product" } func (s *SoldState) Dispense() string { if s.machine.count == 0 { s.machine.SetState(s.machine.soldOutState) return "Oops, out of products" } s.machine.SetState(s.machine.noCoinState) return "Product dispensed" } // SoldOutState 售罄状态 type SoldOutState struct { machine *VendingMachine } func (s *SoldOutState) InsertCoin() string { return "Machine is sold out" } func (s *SoldOutState) EjectCoin() string { return "You can't eject, you haven't inserted a coin yet" } func (s *SoldOutState) SelectProduct() string { return "Machine is sold out" } func (s *SoldOutState) Dispense() string { return "No product dispensed" } // 使用示例 func main() { // 创建一个有3个商品的售货机 vendingMachine := NewVendingMachine(3) fmt.Println(vendingMachine.SelectProduct()) // 需要先投币 fmt.Println(vendingMachine.InsertCoin()) // 投币 fmt.Println(vendingMachine.SelectProduct()) // 选择商品 fmt.Println(vendingMachine.Dispense()) // 出货 fmt.Println(vendingMachine.InsertCoin()) // 再次投币 fmt.Println(vendingMachine.EjectCoin()) // 退币 } ``` ## 适用场景 1. 状态依赖行为 - 对象行为依赖于其状态 - 行为随状态改变而改变 2. 复杂条件语句 - 存在大量状态相关的条件语句 - 需要简化条件分支 3. 状态转换 - 需要在运行时管理状态转换 - 状态转换有一定的规则 ## 优缺点 ### 优点 1. 封装状态转换规则 - 将状态转换显式化 - 使状态转换更容易维护 2. 消除条件分支 - 避免使用if-else语句 - 提高代码的可维护性 3. 状态类可共享 - 状态对象可以共享 - 减少对象数量 ### 缺点 1. 类数量增加 - 每个状态都需要一个类 - 增加系统复杂度 2. 状态转换的显式化 - 状态转换逻辑分散 - 不易管理和维护 ## 实现要点 1. 状态接口设计 - 定义状态行为 - 确保状态一致性 2. 状态转换管理 - 控制状态转换 - 维护状态生命周期 3. 上下文设计 - 管理当前状态 - 委托状态行为 ## 相关模式 1. 策略模式 - 都封装行为 - 但状态模式关注状态转换 2. 单例模式 - 状态对象可以是单例 - 共享状态实例 3. 享元模式 - 可以共享状态对象 - 减少状态实例 ## 总结 状态模式是一种用于管理对象状态的行为型设计模式,它的核心价值在于: 1. 状态封装 - 将状态相关的行为封装到类中 - 使状态转换更加清晰 2. 行为委托 - 将行为委托给状态对象 - 简化对象的行为管理 3. 扩展性 - 易于添加新状态 - 不影响现有代码 在实际开发中,状态模式常用于需要管理复杂状态转换的场景,如工作流、游戏状态、通信协议等。使用状态模式可以让代码更加清晰、易于维护,但也需要注意状态类的数量控制和状态转换的管理。