【最佳实践】Go 状态模式

设计思路

状态模式的核心在于将对象的行为封装在特定的状态类中,使得对象在不同的状态下表现出不同的行为。每个状态实现同一个接口,允许对象在运行时通过改变其内部状态对象来改变其行为。状态模式使得状态转换更加明确,并且易于扩展新的状态和行为。

场景描述

假设我们有一个简单的文档编辑器,文档可以处于不同的编辑状态:草稿、审核、发布。每个状态对应不同的行为,比如在草稿状态下可以编辑内容,在审核状态下可以提交审核,在发布状态下可以查看内容但不能编辑。我们将使用状态模式来实现这一场景。

实现示例

下面是一个使用状态模式实现的 Go 语言示例,展示了一个简单的文档编辑系统:

go 复制代码
package main

import "fmt"

// DocumentState 是状态接口,定义了文档状态的行为
type DocumentState interface {
	Edit() error
	Submit() error
	Publish() error
}

// Document 是包含状态的上下文
type Document struct {
	state DocumentState
}

// SetState 设置文档的当前状态
func (d *Document) SetState(state DocumentState) {
	d.state = state
}

// Edit 触发编辑行为
func (d *Document) Edit() error {
	return d.state.Edit()
}

// Submit 触发提交审核行为
func (d *Document) Submit() error {
	return d.state.Submit()
}

// Publish 触发发布行为
func (d *Document) Publish() error {
	return d.state.Publish()
}

// DraftState 是草稿状态
type DraftState struct {
	document *Document
}

func (s *DraftState) Edit() error {
	fmt.Println("Editing the document.")
	return nil
}

func (s *DraftState) Submit() error {
	fmt.Println("Submitting the document for review.")
	s.document.SetState(&ReviewState{document: s.document})
	return nil
}

func (s *DraftState) Publish() error {
	return fmt.Errorf("document cannot be published directly from draft")
}

// ReviewState 是审核状态
type ReviewState struct {
	document *Document
}

func (s *ReviewState) Edit() error {
	return fmt.Errorf("document cannot be edited during review")
}

func (s *ReviewState) Submit() error {
	return fmt.Errorf("document is already under review")
}

func (s *ReviewState) Publish() error {
	fmt.Println("Publishing the document.")
	s.document.SetState(&PublishedState{document: s.document})
	return nil
}

// PublishedState 是已发布状态
type PublishedState struct {
	document *Document
}

func (s *PublishedState) Edit() error {
	return fmt.Errorf("document cannot be edited after publishing")
}

func (s *PublishedState) Submit() error {
	return fmt.Errorf("document is already published")
}

func (s *PublishedState) Publish() error {
	fmt.Println("Document is already published.")
	return nil
}

func main() {
	// 创建一个文档,并设置初始状态为草稿
	document := &Document{}
	initialState := &DraftState{document: document}
	document.SetState(initialState)

	// 编辑文档
	err := document.Edit()
	if err != nil {
		fmt.Println("Error:", err)
	}

	// 提交文档审核
	err = document.Submit()
	if err != nil {
		fmt.Println("Error:", err)
	}

	// 尝试编辑文档(应失败,因为在审核中)
	err = document.Edit()
	if err != nil {
		fmt.Println("Error:", err)
	}

	// 发布文档
	err = document.Publish()
	if err != nil {
		fmt.Println("Error:", err)
	}

	// 尝试发布文档(应成功,因为已发布)
	err = document.Publish()
	if err != nil {
		fmt.Println("Error:", err)
	}
}

代码解释

  • DocumentState 接口 :定义了文档状态的行为接口,包括 EditSubmitPublish 方法。每个状态实现这些行为。

  • Document 结构体 :代表文档对象,包含一个 DocumentState。通过 SetState 方法可以改变文档的状态。

  • DraftState、ReviewState、PublishedState :分别实现了 DocumentState 接口,表示文档的不同状态。每个状态根据其特性实现了相应的行为。

  • main 函数:演示了如何使用状态模式管理文档的状态转换。文档初始状态为草稿,可以编辑和提交审核;审核状态下可以发布;发布状态下可以查看,但不能编辑或再次发布。

总结

「状态模式」抽象过程的核心是:

  • 每一个状态映射对应行为
  • 行为实现同一个接口interface
  • 行为是内部的一个状态
  • 状态是不断变化的
相关推荐
李匠20244 小时前
C++GO语言微服务之图片、短信验证码生成及存储
开发语言·c++·微服务·golang
读心悦9 小时前
CSS结构性伪类、UI伪类与动态伪类全解析:从文档结构到交互状态的精准选择
css·ui·交互
Cxzzzzzzzzzz13 小时前
Kafka Go客户端--Sarama
中间件·golang·kafka·linq
逍遥德13 小时前
CSS可以继承的样式汇总
前端·css·ui
lyw20561914 小时前
框架篇八股(自用)
状态模式
川川籽14 小时前
hashicorp/raft模块实现的raft集群存在节点跨集群身份冲突问题
golang·go-raft
Asus.Blogs16 小时前
为什么 import _ “github.com/go-sql-driver/mysql“ 要导入但不使用?_ 是什么意思?
sql·golang·github
程序员爱钓鱼17 小时前
跳转语句:break、continue、goto -《Go语言实战指南》
开发语言·后端·golang·go1.19
洛克希德马丁20 小时前
QLineEdit增加点击回显功能
c++·qt·ui
Clown951 天前
Go语言爬虫系列教程(一) 爬虫基础入门
开发语言·爬虫·golang