状态模式,顾名思义,是一种基于有限状态机制的设计模式。在这种设计模式中,行为是由相应的状态来决定的。接下来我们会用一个售卖机的例子来说明下状态模式。为了便于说明,我们把场景简化一下,假设有一台售卖机只卖一种商品,且只有如下四种状态:

  1. 有商品
  2. 无商品
  3. 商品请求中
  4. 已收款

一台售卖机也应该会有多种功能,我们同样做一下简化,假设这台售卖机只有四个功能:

  1. 选择商品
  2. 补充商品
  3. 投币
  4. 吐出商品

什么时候使用状态模式

  • 在一个对象有多种不同状态的时候。对象需要根据当前的请求来改变它的状态

    • 在前面提到的例子中,售卖机将会受到行为的影响从一种状态切换到另一种状态。比如,当“投币”行为结束后,售货机将会从“商品请求中”状态切换到“已收款”状态。
  • 在一个对象需要根据它当前的状态对同一个请求做出不同响应的时候。这个时候使用状态模式可以避免大量的条件声明。
    • 仍然以售卖机为例,当用户想购买商品时,如果售卖机的状态为“有商品”,它就会继续处理,如果售卖机状态为“无商品”,它就会拒绝处理。请注意,这里售卖机根据它“有商品”和“无商品”的状态,对购买商品的请求作出了两种不同的响应。

UML类图

类图如下:

代码

看下代码:

state.go:

type state interface {
addItem(int) error requestItem() error insertMoney(money int) error dispenseItem() error
}

这里简单解释下:

在代码中我们定义了一个State接口,这个接口中有四个函数分别表示了售卖机的四种行为,如下:

  1. 购买商品:addItem(int) error
  2. 请求商品:requestItem() error
  3. 投币:insertMoney(money int) error
  4. 吐出商品:dispenseItem() error

每个具体的状态实现都实现了以上四个函数,并对每种行为发生时该切换到哪种状态,以及如何响应做了处理

每个具体的状态也都嵌入了一个指向当前售卖机的指针,这样以确保状态的切换是发生在这台售卖机上。

vendingMachine.go:

import "fmt"

type vendingMachine struct {
hasItem state
itemRequested state
hasMoney state
noItem state currentState state itemCount int
itemPrice int
} 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 = v.itemCount + count
}

注意这段代码,这里面没有任何条件表达式,所有逻辑处理均由相应的状态实现完成。

下面是具体的状态实现。

hasItemState.go:

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 requestd\n")
i.vendingMachine.setState(i.vendingMachine.itemRequested)
return nil
} func (i *hasItemState) addItem(count int) error {
fmt.Printf("%d items added\n", 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")
}

hasMoneyState.go:

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
}

itemRequestedState.go:

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 {
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")
}

noItemState.go:

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")
}

下面是场景实现main.go:

import (
"fmt"
"log"
) func main() {
vendingMachine := newVendingMachine(1, 10)
err := vendingMachine.requestItem()
if err != nil {
log.Fatalf(err.Error())
}
err = vendingMachine.insertMoney(10)
if err != nil {
log.Fatalf(err.Error())
}
err = vendingMachine.dispenseItem()
if err != nil {
log.Fatalf(err.Error())
} fmt.Println()
err = vendingMachine.addItem(2)
if err != nil {
log.Fatalf(err.Error())
} fmt.Println() err = vendingMachine.requestItem()
if err != nil {
log.Fatalf(err.Error())
} err = vendingMachine.insertMoney(10)
if err != nil {
log.Fatalf(err.Error())
} err = vendingMachine.dispenseItem()
if err != nil {
log.Fatalf(err.Error())
}
} func newVendingMachine(itemCount, itemPrice int) *vendingMachine {
v := &vendingMachine{
itemCount: itemCount,
itemPrice: itemPrice,
}
hasItemState := &hasItemState{
vendingMachine: v,
}
itemRequestedState := &itemRequestedState{
vendingMachine: v,
}
hasMoneyState := &hasMoneyState{
vendingMachine: v,
}
noItemState := &noItemState{
vendingMachine: v,
} v.setState(hasItemState)
v.hasItem = hasItemState
v.itemRequested = itemRequestedState
v.hasMoney = hasMoneyState
v.noItem = noItemState
return v
}

执行后输出为:

Item requestd
Money entered is ok
Dispensing Item Adding 2 items Item requestd
Money entered is ok
Dispensing Item

代码已上传至GitHub: zhyea / go-patterns / state-pattern

End!!

GoLang设计模式14 - 状态模式的更多相关文章

  1. python设计模式之状态模式

    python设计模式之状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态 ...

  2. 【转】设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  3. 设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  4. 乐在其中设计模式(C#) - 状态模式(State Pattern)

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

  5. 折腾Java设计模式之状态模式

    原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...

  6. Golang设计模式—简单工厂模式(Simple Factory Pattern)

    Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...

  7. 北风设计模式课程---状态模式State(对象行为型)

    北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...

  8. js设计模式——5.状态模式

    js设计模式——5.状态模式 代码演示 /*js设计模式——状态模式*/ // 状态(红灯,黄灯,绿灯) class State { constructor(color) { this.color = ...

  9. 设计模式2——状态模式State

    参考链接: 设计模式之状态模式:https://www.cnblogs.com/haoerlv/p/7777789.html 设计模式系列之状态模式:https://www.jianshu.com/p ...

随机推荐

  1. 简单易行的美化方案:Ubuntu 18.04 把启动过程中的紫色美化为黑色

    背景 给笔记本装了一个Ubuntu,嫌弃启动的颜色很丑:因此在网上找到了一些修改方法,集成为一个傻瓜脚本. 参考文档: https://askubuntu.com/questions/5065/how ...

  2. CAS邮箱的Express配置

    Configuration for all clients: http://help.cstnet.cn/changjianwenti/youjianshoufa/kehuduan.htm Confi ...

  3. 通过Python收集MySQL MHA 部署及运行状态信息的功能实现

    一. 背景介绍 当集团的MySQL数据库实例数达到2000+.MHA集群规模数百个时,对MHA的及时.高效管理是DBA必须面对的一个挑战.MHA 集群 节点信息 和 运行状态 是管理的基础.本篇幅主要 ...

  4. vue+element UI 使用select元素动态的从后台获取到

    VUE select元素动态的从后台获取到 <el-form-item label="选择店铺"> <el-select v-model="value& ...

  5. 转载 使用wce进行本地和域的hash注入

    参数解释:-l 列出登录的会话和NTLM凭据(默认值)-s 修改当前登录会话的NTLM凭据 参数:<用户名>:<域名>:<LM哈希>:<NT哈希>-r ...

  6. JDK源码阅读(3):AbstractStringBuilder、StringBuffer、StringBuilder类阅读笔记

    AbstractStringBuilder abstract class AbstractStringBuilder implements Appendable, CharSequence{ ... ...

  7. C++学习 2 指针

    指针:指针保存的是数据的地址: #include<iostream> using namespace std; int main() { //1.定义指针 int a = 10; //指针 ...

  8. 土壤稳定性评估(ArcPy实现)

    一.背景 在进行区域土地开发时,需要对整个区域的土壤稳定性评估.应用GIS空间分析方法,能够快速有效地对影响土壤稳定性的因子进行制图并评估打分,通过构建评价体系,利用叠加分析,形成土壤稳定性专题图,以 ...

  9. 初步认识HCIA,什么是计算机网络,拓扑,网络的发展,交换机,路由器,IP,光纤,带宽,广播,ARP......

    HCIA ---- 华为认证初级网络工程师 云技术 --- 云存储 云计算 计算机技术 : ​ --- 抽象语言 -- 电线号的转换 抽象语言 -- 编码 ---- 应用层 编码 --- 二进制 -- ...

  10. 题解 HDU 5279 YJC plays Minecraft

    题目传送门 题目大意 给出\(n\)以及\(a_{1,2,...,n}\),表示有\(n\)个完全图,第\(i\)个完全图大小为\(a_i\),这些完全图之间第\(i\)个完全图的点\(a_i\)与\ ...