Go設(shè)計模式之狀態(tài)模式講解和代碼示例
Go 狀態(tài)模式講解和代碼示例
概念示例
讓我們在一臺自動售貨機(jī)上使用狀態(tài)設(shè)計模式。 為簡單起見, 讓我們假設(shè)自動售貨機(jī)僅會銷售一種類型的商品。 同時, 依然為了簡單起見, 我們假設(shè)自動售貨機(jī)可處于 4 種不同的狀態(tài)中:
- 有商品 (hasItem)
- 無商品 (noItem)
- 商品已請求 (itemRequested)
- 收到紙幣 (hasMoney)
同時, 自動售貨機(jī)也會有不同的操作。 再一次的, 為了簡單起見, 我們假設(shè)其只會執(zhí)行 4 種操作:
- 選擇商品
- 添加商品
- 插入紙幣
- 提供商品
當(dāng)對象可以處于許多不同的狀態(tài)中時應(yīng)使用狀態(tài)設(shè)計模式, 同時根據(jù)傳入請求的不同, 對象需要變更其當(dāng)前狀態(tài)。
在我們的例子中, 自動售貨機(jī)可以有多種不同的狀態(tài), 同時會在這些狀態(tài)之間持續(xù)不斷地互相轉(zhuǎn)換。 我們假設(shè)自動售貨機(jī)處于 商品已請求狀態(tài)中。 在 “插入紙幣” 的操作發(fā)生后, 機(jī)器將自動轉(zhuǎn)換至 收到紙幣狀態(tài)。
根據(jù)其當(dāng)前狀態(tài), 機(jī)器可就相同請求采取不同的行為。 例如, 如果用戶想要購買一件商品, 機(jī)器將在 有商品狀態(tài)時繼續(xù)操作, 而在 無商品狀態(tài)時拒絕操作。
自動售貨機(jī)的代碼不會被這一邏輯污染; 所有依賴于狀態(tài)的代碼都存在于各自的狀態(tài)實(shí)現(xiàn)中。
vendingMachine.go: 背景
package main
import "fmt"
type VendingMachine struct {
hasItem State
itemRequested State
hasMoney State
noItem State
currentState State // 當(dāng)前狀態(tài)
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: 狀態(tài)接口
package main
type State interface {
addItem(int) error
requestItem() error
insertMoney(money int) error
dispenseItem() error
}noItemState.go: 具體狀態(tài)
package main
import "fmt"
// 無貨狀態(tài)
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: 具體狀態(tài)
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: 具體狀態(tài)
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: 具體狀態(tài)
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: 執(zhí)行結(jié)果
Item requested
Money entered is ok
Dispensing Item
================
Adding 2 itemsItem requested
Money entered is ok
Dispensing Item
到此這篇關(guān)于Go設(shè)計模式之狀態(tài)模式講解和代碼示例的文章就介紹到這了,更多相關(guān)Go狀態(tài)模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang利用casbin實(shí)現(xiàn)權(quán)限驗(yàn)證詳解
Casbin是一個強(qiáng)大的、高效的開源訪問控制框架,其權(quán)限管理機(jī)制支持多種訪問控制模型,Casbin只負(fù)責(zé)訪問控制。本文將利用casbin實(shí)現(xiàn)權(quán)限驗(yàn)證功能,需要的可以參考一下2023-02-02
Go項(xiàng)目實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能
無論是優(yōu)雅關(guān)機(jī)還是優(yōu)雅重啟歸根結(jié)底都是通過監(jiān)聽特定系統(tǒng)信號,然后執(zhí)行一定的邏輯處理保障當(dāng)前系統(tǒng)正在處理的請求被正常處理后再關(guān)閉當(dāng)前進(jìn)程,這篇文章主要介紹了Go實(shí)現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟 ,需要的朋友可以參考下2022-10-10
GO語言創(chuàng)建錢包并遍歷錢包(wallet)的實(shí)現(xiàn)代碼
比特幣錢包實(shí)際上是一個密鑰對,當(dāng)你安裝 一個錢包應(yīng)用,或者是使用一個比特幣客戶端來生成一個新地址是,他就會為你生成一個密鑰對,今天通過本文給大家分享go語言遍歷錢包的相關(guān)知識,一起看看吧2021-05-05
Go實(shí)現(xiàn)用戶每日限額的方法(例一天只能領(lǐng)三次福利)
這篇文章主要介紹了Go實(shí)現(xiàn)用戶每日限額的方法(例一天只能領(lǐng)三次福利)2022-01-01
Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼
本文主要介紹了Go實(shí)現(xiàn)替換(覆蓋)文件某一行內(nèi)容的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

