Go设计模式之状态模式讲解和代码示例

 更新时间:2023年08月11日 08:27:09   作者:demo007x  
状态是一种行为设计模式, 让你能在一个对象的内部状态变化时改变其行为,该模式将与状态相关的行为抽取到独立的状态类中, 让原对象将工作委派给这些类的实例, 而不是自行进行处理,本文将通过代码示例给大家简单的介绍一下Go状态模式

Go 状态模式讲解和代码示例

概念示例

让我们在一台自动售货机上使用状态设计模式。 为简单起见, 让我们假设自动售货机仅会销售一种类型的商品。 同时, 依然为了简单起见, 我们假设自动售货机可处于 4 种不同的状态中:

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

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

  • 选择商品
  • 添加商品
  • 插入纸币
  • 提供商品

当对象可以处于许多不同的状态中时应使用状态设计模式, 同时根据传入请求的不同, 对象需要变更其当前状态。

在我们的例子中, 自动售货机可以有多种不同的状态, 同时会在这些状态之间持续不断地互相转换。 我们假设自动售货机处于 商品已请求状态中。 在 “插入纸币” 的操作发生后, 机器将自动转换至 收到纸币状态。

根据其当前状态, 机器可就相同请求采取不同的行为。 例如, 如果用户想要购买一件商品, 机器将在 有商品状态时继续操作, 而在 无商品状态时拒绝操作。

自动售货机的代码不会被这一逻辑污染; 所有依赖于状态的代码都存在于各自的状态实现中。

vendingMachine.go: 背景

package main
import "fmt"
type VendingMachine struct {
	hasItem       State
	itemRequested State
	hasMoney      State
	noItem        State
	currentState State // 当前状态
	itemCount    int
	itemPrice    int
}
func newVendingMachine(itemCount, itemPrice int) *VendingMachine {
	v := &VendingMachine{
		itemCount: itemCount,
		itemPrice: itemPrice,
	}
	hasItemState := &HasItemState{vendingMachine: v}
	itemRequestState := &ItemRequestedState{vendingMachine: v}
	hasMoneyState := &HasMoneyState{vendingMachine: v}
	noItemState := &NoItemState{vendingMachine: v}
	v.setState(hasItemState)
	v.hasItem = hasItemState
	v.itemRequested = itemRequestState
	v.hasMoney = hasMoneyState
	v.noItem = noItemState
	return 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 = count + v.itemCount
}

state.go: 状态接口

package main
type State interface {
	addItem(int) error
	requestItem() error
	insertMoney(money int) error
	dispenseItem() error
}

noItemState.go: 具体状态

package main
import "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 main
import "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 requested \n")
	i.vendingMachine.setState(i.vendingMachine.itemRequested)
	return nil
}
func (i *HasItemState) addItem(count int) error {
	fmt.Printf("%d item added", 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 main
import "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 main
import "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 - 1
	if i.vendingMachine.itemCount == 0 {
		i.vendingMachine.setState(i.vendingMachine.noItem)
	} else {
		i.vendingMachine.setState(i.vendingMachine.hasItem)
	}
	return nil
}

main.go: 客户端代码

package main
import (
	"fmt"
	"log"
)
func main() {
	vendingMachine := newVendingMachine(1, 10)
	// 获取一个商品
	if err := vendingMachine.requestItem(); err != nil {
		log.Fatalf(err.Error())
	}
	if err := vendingMachine.insertMoney(10); err != nil {
		log.Fatal(err.Error())
	}
	if err := vendingMachine.dispenseItem(); err != nil {
		log.Fatal(err.Error())
	}
	fmt.Println("================")
	if err := vendingMachine.addItem(2); err != nil {
		log.Fatal(err.Error())
	}
	fmt.Println()
	if err := vendingMachine.requestItem(); err != nil {
		log.Fatal(err.Error())
	}
	if err := vendingMachine.insertMoney(10); err != nil {
		log.Fatal(err.Error())
	}
	if err := vendingMachine.dispenseItem(); err != nil {
		log.Fatal(err.Error())
	}
}

output.txt: 执行结果

Item requested 
Money entered is ok
Dispensing Item
================
Adding 2 items 

Item requested 
Money entered is ok
Dispensing Item

到此这篇关于Go设计模式之状态模式讲解和代码示例的文章就介绍到这了,更多相关Go状态模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang利用casbin实现权限验证详解

    Golang利用casbin实现权限验证详解

    Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型,Casbin只负责访问控制。本文将利用casbin实现权限验证功能,需要的可以参考一下
    2023-02-02
  • 浅谈go中切片比数组好用在哪

    浅谈go中切片比数组好用在哪

    数组和切片都是常见的数据结构,本文将介绍Go语言中数组和切片的基本概念,同时详细探讨切片的优势,感兴趣的可以了解下
    2023-06-06
  • Golang中Options模式的使用

    Golang中Options模式的使用

    选项模式是一种设计模式,允许通过提供选项自定义行为,Golang中的应用广泛,尤其是库和框架设计中,本文深入探讨Golang中选项模式的实现,包括函数选项和结构体选项两种方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • Go项目实现优雅关机与平滑重启功能

    Go项目实现优雅关机与平滑重启功能

    无论是优雅关机还是优雅重启归根结底都是通过监听特定系统信号,然后执行一定的逻辑处理保障当前系统正在处理的请求被正常处理后再关闭当前进程,这篇文章主要介绍了Go实现优雅关机与平滑重启 ,需要的朋友可以参考下
    2022-10-10
  • Golang如何使用go.mod配置加载本地模块

    Golang如何使用go.mod配置加载本地模块

    这篇文章主要介绍了Golang如何使用go.mod配置加载本地模块问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • GO语言创建钱包并遍历钱包(wallet)的实现代码

    GO语言创建钱包并遍历钱包(wallet)的实现代码

    比特币钱包实际上是一个密钥对,当你安装 一个钱包应用,或者是使用一个比特币客户端来生成一个新地址是,他就会为你生成一个密钥对,今天通过本文给大家分享go语言遍历钱包的相关知识,一起看看吧
    2021-05-05
  • Go实现用户每日限额的方法(例一天只能领三次福利)

    Go实现用户每日限额的方法(例一天只能领三次福利)

    这篇文章主要介绍了Go实现用户每日限额的方法(例一天只能领三次福利)
    2022-01-01
  • Golang并发利器sync.Once的用法详解

    Golang并发利器sync.Once的用法详解

    在某些场景下,我们需要初始化一些资源。有时会采用延迟初始化的方式,在真正需要资源的时候才进行初始化。在这种情况下,Go语言中的sync.Once提供一个优雅且并发安全的解决方案,本文将对其进行详细介绍
    2023-04-04
  • 详解Golang中日志库glog的使用

    详解Golang中日志库glog的使用

    golang/glog 是 C++ 版本 google/glog 的 Go 版本实现,基本实现了原生 glog 的日志格式,下面大家就跟随小编一起了解一下glog的具体使用吧
    2023-09-09
  • Go实现替换(覆盖)文件某一行内容的示例代码

    Go实现替换(覆盖)文件某一行内容的示例代码

    本文主要介绍了Go实现替换(覆盖)文件某一行内容的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论