您现在的位置是:亿华云 > 系统运维

我是状态机, 一颗永远骚动的机器引擎

亿华云2025-10-03 02:20:29【系统运维】7人已围观

简介本文转载自微信公众号「精益码农」,作者小码甲 。转载本文请联系精益码农公众号。状态机是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。看起来好像对象改变了它的类。请仔细理解上面每一个字。我们

本文转载自微信公众号「精益码农」,状态作者小码甲 。机颗转载本文请联系精益码农公众号。永远

状态机是骚动一种行为设计模式,它允许对象在其内部状态改变时改变其行为。器引擎看起来好像对象改变了它的状态类。

请仔细理解上面每一个字。机颗

我们以自动售货机为例,永远为简化演示,骚动我们假设自动售货机只有1种商品,器引擎 故自动售货机有itemCount 、状态itemPrice 2个属性。机颗

不考虑动作的永远前后相关性,自动售货机对外暴露4种行为:

给自动售货机加货 addItem 选择商品 requestItem 付钱 insertMoney 出货 dispenseItem

重点来了,骚动当发生某种行为,器引擎自动售货机会进入如下4种状态之一, 并据此状态做出特定动作, 之后进入另外一种状态.....

有商品 hasItem 无商品 noItem 已经选好商品 itemRequested 已付钱 hasMoney

当对象可能处于多种不同的状态之一、根据传入的动作更改当前的状态, 继续接受后续动作,状态再次发生变化.....

这样的模式类比于机器引擎,周而复始的工作和状态转化,这也是状态机的亿华云计算定语叫“机Machine”的原因。

有了以上思路,我们尝试沟通UML 伪代码:

状态机设计模式的伪代码实现:

所谓的机器Machine维护了状态切换的上下文 机器对外暴露的行为,驱动机器的状态变更, 行为和状态是有因果关系的 机器到达特定的状态 只具备特定的行为,其他行为是不被允许的, 这在外面看,貌似是对象改变了原类的行为

下面使用golang实现了 状态机设计模型:这里你也可以看下golang 是如何体现OOP中的类继承、接口实现

goodMachine:状态变更上下文

package main import (  "fmt"  "reflect" ) type goodMachine struct {   currentState state  itemCount    int  itemPrice    int } func newGoodMachine(itemCount, itemPrice int) *goodMachine {   v := &goodMachine{    itemCount: itemCount,   itemPrice: itemPrice,  }  if itemCount <= 0 {    v.setState(&noItemState{ v}) // 实现state接口的是*noItemState 指针类型  } else {    v.setState(&hasItemState{ v})  }  return v } func (v *goodMachine) setState(s state) {   fmt.Println("enter state: ", reflect.TypeOf(s))  v.currentState = s } func (v *goodMachine) requestItem() error {   return v.currentState.requestItem() } func (v *goodMachine) addItem(count int) error {   return v.currentState.addItem(count) } func (v *goodMachine) insertMoney(money int) error {   return v.currentState.insertMoney(money) } func (v *goodMachine) incrementItemCount(count int) {   v.itemCount += count } func (v goodMachine) dispenseItem() error {   return v.currentState.dispenseItem() } 

自动售货机对外的行为,被委托给特定的state对象

state:自动售货机对外暴露的行为

package main //  代表某种状态,云服务器能接受的某种动作 type state interface {   addItem(count int) error  requestItem() error  insertMoney(money int) error  dispenseItem() error } 

noItemState : 无商品

package main import "fmt" type noItemState struct {   *goodMachine // 存在匿名类型 goodMachine,类型是*goodMachine } //  给自动售货机供货-----> 有货状态 func (i *noItemState) addItem(count int) error {   i.incrementItemCount(count)  i.setState(&hasItemState{ i.goodMachine})  return nil } func (i *noItemState) requestItem() error {   return fmt.Errorf("item out of  stock") } 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") } // golang: 使用指针接受者实现了state接口的全部函数,那么隐式表明*noItemState 指针类型实现了State接口 

注意:noItemState 结构体内定义了 goodMachine, 就表明noItemState继承了goodMachine类 ;

指针接受者 noItemState实现了state接口的所有函数,那么我们就说*noItemState实现了state接口。

hasItemState: 有商品

package main import "fmt" type hasItemState struct {   *goodMachine } func (v *hasItemState) addItem(count int) error {   v.incrementItemCount(count)  return nil } // 有人选择了商品---> 没货状态/已经选定商品 func (v *hasItemState) requestItem() error {   if v.goodMachine.itemCount == 0 {    v.setState(&noItemState{ v.goodMachine})   return fmt.Errorf("no item present")  }  fmt.Print("item  requested\n")  v.setState(&itemRequestedState{ v.goodMachine})  return nil } func (v *hasItemState) insertMoney(money int) error {   return fmt.Errorf("Please select item first") } func (v *hasItemState) dispenseItem() error {   return fmt.Errorf("Please select item first") } 

itemRequestedState:有人选定商品

package main import "fmt" type itemRequestedState struct {   *goodMachine } func (i *itemRequestedState) addItem(count int) error {   return fmt.Errorf("shopping is  in  process") } func (i *itemRequestedState) requestItem() error {   return fmt.Errorf("item already requested") } // 付钱----> 已收钱状态 func (i *itemRequestedState) insertMoney(money int) error {   if money < i.goodMachine.itemPrice {    fmt.Errorf("insert money is less, please insert %d", i.goodMachine)  }  fmt.Println("money entered is ok")  i.setState(&hasMoneyState{ i.goodMachine})  return nil } func (i *itemRequestedState) dispenseItem() error {   return fmt.Errorf("please insert money first") } 

hasMoneyState:已付钱

package main import "fmt" type hasMoneyState struct {   *goodMachine } func (i *hasMoneyState) addItem(count int) error {   return fmt.Errorf("shopping is in process") } func (i *hasMoneyState) requestItem() error {   return fmt.Errorf("shopping is in process") } func (i *hasMoneyState) insertMoney(money int) error {   return fmt.Errorf("already pay money") } func (i *hasMoneyState) dispenseItem() error {   fmt.Println("dispensing item")  i.goodMachine.itemCount = i.goodMachine.itemCount - 1  if i.goodMachine.itemCount == 0 {    i.setState(&noItemState{ i.goodMachine})  } else {    i.setState(&hasItemState{ i.goodMachine})  }  return nil } 

main.go 执行

package main import (   "fmt"   "log" ) func main() {    goodMachine := newGoodMachine(1, 10)   err := goodMachine.requestItem()   if err != nil {      log.Fatalf(err.Error())   }   err = goodMachine.insertMoney(10)   if err != nil {      log.Fatalf(err.Error())   }   err = goodMachine.dispenseItem()   if err != nil {      log.Fatalf(err.Error())   }   fmt.Println()   err = goodMachine.requestItem()   if err != nil {      log.Fatalf(err.Error())   }   err = goodMachine.insertMoney(10)   if err != nil {      log.Fatal(err.Error())   }   err = goodMachine.dispenseItem()   if err != nil {      log.Fatalf(err.Error())   } } 

初始化了商品数量为1,价格为10 的自动售货机,连续掏10元钱买两次, 随时打印状态, 输出如下:

enter state:  *main.hasItemState item  requested enter state:  *main.itemRequestedState money entered is ok enter state:  *main.hasMoneyState      dispensing item enter state:  *main.noItemState        2021/08/11 17:39:45 item out of  stock exit status 1 

状态机为什么定语是机器?Machine?

状态机表现了:

对象的状态受外界行为所影响,不断的切换,到达特定的状态又只能接受特定的行为, 真实生动的体现了机器Machine引擎的特征。

本文示例亦是学习golang OOP编程的范例,golang 类继承、接口实现实在是太秀了。 

github: https://github.com/zaozaoniao/statemachine

很赞哦!(445)