Golang 开发者Golang开发深入浅出golang

Golang设计模式——状态模式

2019-04-16  本文已影响2人  CodePanda_Li

状态模式及其结构

状态模式(State):当一个对象的内部状态发生改变时,会导致其行为的改变,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。

模式的结构

UML

状态模式.png

在状态模式结构图中包含如下几个角色:

代码示例

当今社会,论坛贴吧很多,我们也会加入感兴趣的论坛,偶尔进行发言,但有时却会发现不能发帖了,原来是昨天的某个帖子引发了口水战,被举报了。这里就用论坛发帖为例,简单用代码描述一下:

帖子代码示例图.png

假设有三种状态,normal(正常),restricted(受限),closed(封号),判断依据是一个健康值(这里只是假设)。

2.1不用状态模式

/* @Time    : 2018/8/10 下午3:16
 **@Author  : panda
 **@Email   : codepanda_li@163.com
 **@File    : account.go
 **@Software: GoLand
 */
package account

import "fmt"

type AccountState int

const (
   NORMAL     AccountState = iota //正常0
   RESTRICTED                     //受限
   CLOSED                         //封号
)

type Account struct {
   State       AccountState
   HealthValue int
}

func NewAccount(health int) *Account {
   a := &Account{
      HealthValue: health,
   }
   a.changeState()
   return a
}

///看帖
func (a *Account) View() {
   if a.State == NORMAL || a.State == RESTRICTED {
      fmt.Println("正常看帖")
   } else if a.State == CLOSED {
      fmt.Println("账号被封,无法看帖")
   }

}

///评论
func (a *Account) Comment() {
   if a.State == NORMAL || a.State == RESTRICTED {
      fmt.Println("正常评论")
   } else if a.State == CLOSED {
      fmt.Println("抱歉,你的健康值小于-10,不能评论")
   }

}

///发帖
func (a *Account) Post() {
   if a.State == NORMAL {
      fmt.Println("正常发帖")
   } else if a.State == RESTRICTED || a.State == CLOSED {
      fmt.Println("抱歉,你的健康值小于0,不能发帖")
   }
}

func (a *Account) changeState() {
   if a.HealthValue <= -10 {
      a.State = CLOSED
   } else if a.HealthValue > -10 && a.HealthValue <= 0 {
      a.State = RESTRICTED
   } else if a.HealthValue > 0 {
      a.State = NORMAL
   }
}

///给账户设定健康值
func (a *Account) SetHealth(value int) {
   a.HealthValue = value
   a.changeState()
}

上面的代码很简单,能够实现需要的功能,但是却有几个问题:

2.2使用状态模式

状态模式可以在一定程度上解决上述问题,在状态模式中将对象在每一个状态下的行为和状态转移语句封装在一个个状态类中,通过这些状态类来分散冗长的条件转移语句,让系统具有更好的灵活性和可扩展性。

/* @Time    : 2018/8/10 下午3:37
 **@Author  : panda
 **@Email   : codepanda_li@163.com
 **@File    : account.go
 **@Software: GoLand
 */
package saccount

import "fmt"

type Account struct {
   State       ActionState
   HealthValue int
}
func NewAccount(health int) *Account {
   a := &Account{
      HealthValue: health,
   }
   a.changeState()
   return a
}

func (a *Account)View()  {
   a.State.View()
}

func (a *Account)Comment()  {
   a.State.Comment()
}
func (a *Account)Post()  {
   a.State.Post()
}
type ActionState interface {
   View()
   Comment()
   Post()
}

type CloseState struct {

}

func (c *CloseState)View()  {
   fmt.Println("账号被封,无法看帖")
}

func (c *CloseState)Comment()  {
   fmt.Println("抱歉,你的健康值小于-10,不能评论")
}
func (c *CloseState)Post()  {
   fmt.Println("抱歉,你的健康值小于0,不能发帖")
}

type RestrictedState struct {

}
func (r *RestrictedState)View()  {
   fmt.Println("正常看帖")
}

func (r *RestrictedState)Comment()  {
   fmt.Println("正常评论")
}
func (r *RestrictedState)Post()  {
   fmt.Println("抱歉,你的健康值小于0,不能发帖")
}

type NormalState struct {

}
func (n *NormalState)View()  {
   fmt.Println("正常看帖")
}

func (n *NormalState)Comment()  {
   fmt.Println("正常评论")
}
func (n *NormalState)Post()  {
   fmt.Println("正常发帖")
}
func (a *Account) changeState() {
   if a.HealthValue <= -10 {
      a.State = &CloseState{}
   } else if a.HealthValue > -10 && a.HealthValue <= 0 {
      a.State = &RestrictedState{}
   } else if a.HealthValue > 0 {
      a.State = &NormalState{}
   }
}

///给账户设定健康值
func (a *Account) SetHealth(value int) {
   a.HealthValue = value
   a.changeState()
}

优点和缺点

优点

状态模式的主要优点如下:

缺点

状态模式的主要缺点如下:

适用环境

在以下情况下可以使用状态模式:

模式应用

状态模式在工作流或游戏等类型的软件中得以广泛使用,甚至可以用于这些系统的核心功能设计,如在政府OA办公系统中,一个批文的状态有多种:尚未办理;正在办理;正在批示;正在审核;已经完成等各种状态,而且批文状态不同时对批文的操作也有所差异。使用状态模式可以描述工作流对象(如批文)的状态转换以及不同状态下它所具有的行为。

说明一下,这个贴子的示例是我印象中看过一个java的对状态模式的实现,觉得很恰当明了,然后自己用golang实现了一遍,现在只有goalng示例代码,忘记了那篇java的出处了。对那个java的作者表示敬意。

上一篇 下一篇

猜你喜欢

热点阅读