@@ -458,24 +458,24 @@ func TestVendingMachine(t *testing.T) {
458458
459459### 实现说明
460460
461- 1 . Context 持有 State:VendingMachine 结构体持有所有可能的状态实例(如 hasItemState 等),并在 currentState 字段中记录当前激活的状态。
462- 2 . 委托机制:VendingMachine 的操作方法(如 RequestItem)并不直接执行业务逻辑,而是直接调用 currentState.RequestItem(),实现了行为的动态切换。
463- 3 . 循环依赖处理:在 Go 语言中,具体状态类(如 HasItemState)通常需要持有 VendingMachine 的引用以便调用 SetState 触发状态流转。为了避免包的循环导入(import cycle),通常将 Context 和 State 接口定义在同一个包中。
464- 4 . 状态流转:状态的切换逻辑被封装在具体状态类的方法中(例如 HasMoneyState.DispenseItem 执行完后,根据库存判断是切换回 HasItemState 还是 NoItemState)。这使得状态流转逻辑局部化,便于阅读。
461+ 1 . ` Context ` 持有 ` State:VendingMachine ` 结构体持有所有可能的状态实例(如 ` hasItemState ` 等),并在 ` currentState ` 字段中记录当前激活的状态。
462+ 2 . 委托机制:` VendingMachine ` 的操作方法(如 ` RequestItem ` )并不直接执行业务逻辑,而是直接调用 ` currentState.RequestItem() ` ,实现了行为的动态切换。
463+ 3 . 循环依赖处理:在 Go 语言中,具体状态类(如 ` HasItemState ` )通常需要持有 ` VendingMachine ` 的引用以便调用 ` SetState ` 触发状态流转。为了避免包的循环导入(` import cycle ` ),通常将 ` Context ` 和 ` State ` 接口定义在同一个包中。
464+ 4 . 状态流转:状态的切换逻辑被封装在具体状态类的方法中(例如 ` HasMoneyState.DispenseItem ` 执行完后,根据库存判断是切换回 ` HasItemState ` 还是 ` NoItemState ` )。这使得状态流转逻辑局部化,便于阅读。
465465
466466## 优点与缺点
467467
468468** 优点:**
469469
470470- 封装性强:将与特定状态相关的行为局部化到一个类中,并且将不同状态的行为分割开来。
471- - 消除条件语句:避免了在 Context 类中出现大量的 if-else 或 switch-case 语句,代码更清晰。
472- - 显式转换:状态转换在代码中是显式的(通过 SetState),而不是通过修改某些变量值(如 status = 1)隐式实现。
473- - 符合开闭原则:新增状态只需增加新的具体状态类,无需修改 Context 源码。
471+ - 消除条件语句:避免了在 ` Context ` 类中出现大量的 ` if-else ` 或 ` switch-case ` 语句,代码更清晰。
472+ - 显式转换:状态转换在代码中是显式的(通过 ` SetState ` ),而不是通过修改某些变量值(如 ` status = 1 ` )隐式实现。
473+ - 符合开闭原则:新增状态只需增加新的具体状态类,无需修改 ` Context ` 源码。
474474
475475** 缺点:**
476476
477477- 类爆炸:如果状态很多,会产生大量的具体状态类,增加系统复杂度。
478- - 依赖耦合:具体状态类通常需要依赖 Context 类来执行状态切换,导致耦合度较高。
478+ - 依赖耦合:具体状态类通常需要依赖 ` Context ` 类来执行状态切换,导致耦合度较高。
479479- 逻辑分散:状态流转逻辑分散在各个具体状态类中,不如集中在一个地方(如状态机表)容易总览全局。
480480
481481## 适用场景
@@ -485,14 +485,14 @@ func TestVendingMachine(t *testing.T) {
485485- 行为随状态改变:对象的行为依赖于其状态(属性),并且必须在运行时根据状态改变其行为。
486486- 条件语句复杂:代码中包含大量与对象状态有关的条件语句,导致代码难以维护。
487487- 工作流/订单系统:如订单状态(待支付、已支付、发货、收货、取消),审批流(草稿、待审批、驳回、通过)等场景。
488- - TCP 连接:如 TCP 连接的不同状态(Established, Listening, Closed)对应不同的行为。
488+ - TCP 连接:如 TCP 连接的不同状态(` Established ` , ` Listening ` , ` Closed ` )对应不同的行为。
489489
490490## 注意事项
491491
492- - Go 语言特性:Go 不支持类继承,状态模式通过接口(Interface)和组合(Composition)实现。
493- - 并发安全:在并发环境下,如果多个 Goroutine 同时操作 Context,需要在 Context(如 VendingMachine)的方法中加锁(sync.Mutex),以防止状态切换时出现数据竞争。
494- - 状态复用:如果具体状态类没有内部成员变量(无状态的对象),可以设计为单例模式,在多个 Context 实例间共享,以节省内存。
495- - 与策略模式的区别:策略模式通常由客户端指定使用哪种策略,且策略之间通常相互独立;而状态模式的状态由 Context 或 状态自身管理,且状态之间存在流转关系。
492+ - Go 语言特性:Go 不支持类继承,状态模式通过接口(` Interface ` )和组合(` Composition ` )实现。
493+ - 并发安全:在并发环境下,如果多个 ` Goroutine ` 同时操作 ` Context ` ,需要在 ` Context ` (如 ` VendingMachine ` )的方法中加锁(` sync.Mutex ` ),以防止状态切换时出现数据竞争。
494+ - 状态复用:如果具体状态类没有内部成员变量(无状态的对象),可以设计为单例模式,在多个 ` Context ` 实例间共享,以节省内存。
495+ - 与策略模式的区别:策略模式通常由客户端指定使用哪种策略,且策略之间通常相互独立;而状态模式的状态由 ` Context ` 或 状态自身管理,且状态之间存在流转关系。
496496
497497## 参考资料
498498
0 commit comments