设计模式学习-使用go实现状态模式
状态模式
定义
状态模式(state):当一个条件的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的的条件表达式过于复杂,把状态的判断逻辑转移到表示不同状态的一些列类当中,可以把复杂的判断逻辑简化。
如果状态判断很简单,就没必要使用状态模式了。
状态机
状态机有3个组成部分:状态(State)、事件(Event)、动作(Action)。
状态机的实现方式有三种:
1、分支逻辑法;
就是参照状态转移图,将每一个状态转移,原模原样地直译成代码。这样编写的代码会包含大量的if-else或switch-case分支判断逻辑,甚至是嵌套的分支判断逻辑。
2、查表法;
就是把对应的状态,以及状态对应的时间放入到数据或者 map 中,这样通过根据业务的状态,查询数据或者 map 就能找到对应需要执行的事件。
对于状态很多、状态转移比较复杂的状态机来说,查表法比较合适。通过二维数组来表示状态转移图,能极大地提高代码的可读性和可维护性。
3、状态模式。
如果状态对应的执行操作很复杂,需要一些列的复杂的逻辑操作,这时候就需要引入状态模式了。
优点
1、将与特定状态相关的代码放在单独的类中;
2、无需修改已有状态类和上下文就能引入新状态;
3、通过消除臃肿的状态机条件语句简化上下文代码。
缺点
1、状态模式的使用必然会增加系统类和对象的个数;
2、如果状态机只有几个状态,或者很少发生改变,使用状态模式反而会使系统变的复杂。
适用范围
1、如果对象需要根据自身当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式;
2、如果某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用该模式;
3、当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式。
代码实现
栗子:
比如公司员工,一般会有小组长,经理,总经理等职务,每个职务处理的工作内容,拥有的权限责任是不同的,不同的岗位的职责就可以通过状态模式来表示。
type RankState string
const (
Employee RankState = "employee" // 员工
GroupLeader RankState = "groupLeader" // 小组长
Manager RankState = "manager" // 经理
GeneralManager RankState = "generalManager" // 总经理
)
type CompanyState interface {
getRankState() RankState
salary(*CompanyEmployeeMachine) int
haveRight(*CompanyEmployeeMachine) []string
promotion(*CompanyEmployeeMachine)
}
// CompanyEmployee
type CompanyEmployee struct {
}
func (ce *CompanyEmployee) getRankState() RankState {
return Employee
}
func (ce *CompanyEmployee) salary(cm *CompanyEmployeeMachine) int {
return cm.salary
}
func (ce *CompanyEmployee) promotion(cm *CompanyEmployeeMachine) {
cm.salary += 1000
cm.right = append(cm.right, "绩效奖金")
cm.companyState = &CompanyGroupLeader{}
}
func (ce *CompanyEmployee) haveRight(cm *CompanyEmployeeMachine) []string {
return cm.right
}
// CompanyGroupLeader
type CompanyGroupLeader struct {
}
func (ce *CompanyGroupLeader) getRankState() RankState {
return GroupLeader
}
func (ce *CompanyGroupLeader) salary(cm *CompanyEmployeeMachine) int {
return cm.salary
}
func (ce *CompanyGroupLeader) promotion(cm *CompanyEmployeeMachine) {
cm.salary += 1000
cm.companyState = &CompanyGroupLeader{}
}
func (ce *CompanyGroupLeader) haveRight(cm *CompanyEmployeeMachine) []string {
return cm.right
}
type CompanyEmployeeMachine struct {
salary int
right []string
companyState CompanyState
}
func InitCompanyEmployeeMachine() *CompanyEmployeeMachine {
return &CompanyEmployeeMachine{
salary: 1000,
right: []string{
"休假,年终奖",
},
companyState: &CompanyEmployee{},
}
}
func (m *CompanyEmployeeMachine) HaveRight() []string {
return m.companyState.haveRight(m)
}
func (m *CompanyEmployeeMachine) Salary() int {
return m.companyState.salary(m)
}
func (m *CompanyEmployeeMachine) GetRankState() RankState {
return m.companyState.getRankState()
}
func (m *CompanyEmployeeMachine) Promotion() {
m.companyState.promotion(m)
}
测试代码
func TestCompanyEmployee(t *testing.T) {
cem := InitCompanyEmployeeMachine()
fmt.Println("员工的职级", cem.GetRankState(), ";员工的薪水", cem.Salary(), ";员工的待遇", cem.HaveRight())
// 晋级
cem.Promotion()
fmt.Println("员工的职级", cem.GetRankState(), ";员工的薪水", cem.Salary(), ";员工的待遇", cem.HaveRight())
}
输出的内容
员工的职级 employee ;员工的薪水 1000 ;员工的待遇 [休假,年终奖]
员工的职级 groupLeader ;员工的薪水 2000 ;员工的待遇 [休假,年终奖 绩效奖金]
结构图

参考
【文中代码】https://github.com/boilingfrog/design-pattern-learning/tree/master/状态模式
【大话设计模式】https://book.douban.com/subject/2334288/
【极客时间】https://time.geekbang.org/column/intro/100039001
【状态模式】https://boilingfrog.github.io/2021/11/23/使用go实现状态模式/
设计模式学习-使用go实现状态模式的更多相关文章
- C#设计模式学习笔记:(18)状态模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8032683.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第六个模式--状 ...
- javascript设计模式学习之十六——状态模式
一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...
- 设计模式 ( 十八 ):State状态模式 -- 行为型
1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ellse语句来做状态判断来进行不同情况的处理.但是对 ...
- 设计模式之第21章-状态模式(Java实现)
设计模式之第21章-状态模式(Java实现) “what are you 干啥了?怎么这么萎靡不振?”“昨晚又是补新番,又是补小笼包,睡得有点晚啊.话说杨过的那个雕兄真是太好了,每天给找蛇胆,又陪练武 ...
- 我所理解的设计模式(C++实现)——状态模式(State Pattern)
概述: 看看我们平时用的开关,同样一个开关他有2种状态:开和关,当她处于不同的状态的时候她的行为是不一样的,比如当她是开着的时候,你按她一下,她就变成了关闭状态,她是关着的时候按她一下,她就变成了开着 ...
- Javascript设计模式理论与实战:状态模式
在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将其抽象出来称为状态,我们平时开发时本质上就是对应用程序的各种状态进行切换并作出相应处理.状态模式就是一种适合多种状态场景下的设计模式 ...
- 前端读者 | Javascript设计模式理论与实战:状态模式
本文来自 @狼狼的蓝胖子:链接:http://luopq.com/2015/11/25/design-pattern-state/ 在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将 ...
- 【设计模式】行为型08状态模式(status Pattern)
状态模式(status Pattern) 定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类.其别名为状态对象(Objects for States).与命令模式 ...
- Java设计模式学习笔记(二) 简单工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...
- Java设计模式学习笔记(三) 工厂方法模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 简介 上一篇博客介绍了简单工厂模式,简单工厂模式存在一个很严重的问题: 就是当系统需要引入 ...
随机推荐
- JupyterLab 这插件太强了,Excel灵魂附体
终于把 jupyter notebook 玩明白了 JupyterLab 终于出了 Windows 桌面版 今天向大家介绍一款很有意思的 JupyterLab 插件 -- Mito Mito是Jupy ...
- 【JAVA基础】事务管理
@Transactional 注解的属性介绍 @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.cl ...
- POJ - 2259 Team Queue (队列)
题目链接 https://vjudge.net/problem/POJ-2259 题解 在任何时刻,同一个小组的人只要来到了队伍,就会站在一起,所以我们建立一个队列q0存储队伍中所有小组的编号,再为每 ...
- 2017年第八届 蓝桥杯C组 C/C++决赛题解
蓝桥杯历年国赛真题汇总:Here 1.哥德巴赫分解 哥德巴赫猜想认为:不小于4的偶数都可以表示为两个素数的和. 你不需要去证明这个定理,但可以通过计算机对有限数量的偶数进行分解,验证是否可行. 实际上 ...
- mysql 使用 trim去不掉空格 解决
使用mysql8.0时 发现 有几个空字符串怎么也过滤不掉,使用 is not null.trim()<>''.length()>=1都不行,最后查了一些资料说 trim只能去除半角 ...
- P1228-递归【黄】
这道大递归我一开始就找对了方向,不过了MLE,然后从网上搜索到了一个贼有用的概念--尾递归,即如果递归的下一句就是return且没有返回值或者返回值不含有递归函数则编译器会做优化,不会压入新的函数而是 ...
- poj 1426 深搜
***可能有多个答案,DFS一下找出一个答案即可*** #include<stdio.h> #include<string.h> #include<stdlib.h> ...
- python爬虫-豆瓣电影top250
一.python爬虫简介1.什么是爬虫:网络爬虫,是一种按照一定规则,自动抓取互联网信息的程序或者脚本.由于互联网数据的多样性和资源的有限性,根据用户需求定向抓取相关网页并分析已成为如今主流的爬取策略 ...
- C++数据结构(树)
树是一种递归定义的数据结构,如果树中节点的各子树从左到右是有次序的,不能互换,则称该树为有序树,否则叫无序树. 关于树的节点: 节点拥有的子树的个数叫做节点的度 如果度为0,那么该节点叫做叶节点或终端 ...
- [转帖]如何通过dba_hist_active_sess_history分析数据库历史性能问题
https://www.cnblogs.com/DataArt/p/10018932.html 在数据库运行的过程中,我们有时会碰到数据库hung住的问题,在这个时候很多人会选择尽快让它恢复正常而不是 ...