设计模式:可复用面向对象软件的基础》之状态模式模式

概念

允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。

别名

状态对象

动机

举个例子:在表示网络练的类 TCPConnection。 一个 TCPConnection 对象会表示不同的状态,建立链接(Established), 正在监听 (Listening),链接关闭(Close)。这个时候我们就需要 TCPstate 标是链接状态。TCPState 类为各标是不同的状态的子类声明了一个公共接口。TCPState 的子类实现与特定的状态相关的行为。
TCPConnection 类维护一个表示 TCP 链接当前状态的状态对象 ,一个 TCPState 子类的实例。TCPConnection 类将所有的状态相关的请求委托给这个状态对象。TCPCconnection 使用它的 TCPState 子类实例来执行特定于链接状态的操作。
一旦链接状态发生改变,TCPConnection 对象就会改变它使用的状态对象。例如当前链接从建立状态转为已关闭状态时。TCPConnection 会用一个 TCPClosed 的实例来代替原来的 TCPEstablished 的实例

适用性

在线面两种情况下使用 State 模式

  • 一个对象的行为取决于他的状态,并且必须在运行时根据状态改变它的行为。
  • 一个操作中包含有庞大的多分支的条件语句,且分支依赖该对象的状态。这个状态通常用一个或多个枚举常量表示。

参与者

Context:

  • 定义客户感兴趣的接口
  • 维护一个 ConcreteState 子类实例,这个实例定义当前状态

State"

  • 定义一个接口以封装与 Context 的铁定状态行为相关的行为

ConcreteState subclasses:

  • 每一个子类实现一个与 Context 的状态行为相关的行为

协作

  • Context 将状态相关的请求委托给当前的 ConcreteState 对象处理
  • Context 可将自身作为一个参数传递给处理该请求的状态对象。这是的状态对象在必要时可以访问 Context。
  • Context 是客户使用的主要接口。客户可用状态对象来配置一个 Context,一旦一个 Context 配置完毕,他的客户不再需要直接与状态对象打交道。
  • Context 或 ConcreteState 子类都可以决定哪个状态时另外一个的后继者,以及时在何种条件下进行状态转换

效果

  1. 将特定状态相关行为局部化,并且将不同状态的行为分割开来。state 模式将所有与一个特定状态的相关行为都放入一个对象中。我们或许可以使用 if else 或 switch case 来选择不同的状态,但是在多种状态模式下会导致代码块过大,不易读。例如:HTTPState 状态实现,协议中定义了储如 2xx, 4xx , 3xx ,5xx 四类不同小类的条件,这个时候将每个类分别定义不同的状态类,小类别子类控制大类的子状态值(201,202,301,302)等,会使代码变得更加已读。
  2. 使得状态转化显式化。 当一个对象仅以内部值定义当前状态,其状态表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且,State 对象可以保证 Context 不会发生内部状态不一致的情况,因为从 Context 的角度看,状态转换时原子的,只需要重新绑定一个变量(即 Context 的 State 对象变量 ),而无需为多个变量赋值。
  3. State 对象可被共享

实现

  1. 谁定义状态转换。如果状态转换准则是固定的,那么特可以在 Context 中完全实现。如果规则不确定,Context 需要增加一个接口,让 State 对象显式地设定 Context 的当前状态
  2. 基于表的另一种表示方法。表的好处是其规则性:你可以通过改变数据而不是改变程序代码改变状态转换准则。当然也有一些缺点:
    • 对表的查询通常不如函数调用效率搞。
    • 用统一的,表格的形式转换逻辑是的转换准则变得不够明确难以理解
    • 通常难以加入一些伴随状态变化的一些动作。
      State 模式对状态相关行为进行建模,而表驱动方法着重定义状态转换
  3. 创建和销毁 State 对象。需要时创建,当将要进入的状态运行时是不可知的,并且上下文不经常改变状态时。创建后不做销毁操作,可以预先一次付清创建各个对象的开销。

定义 Status接口

type Status interface{
    Do()
}

定义 StatusObj

// 工作日
type WorkDay struct{}

func (wd *WorkDay) Do(){
    fmt.Println("干活了,干活了!")
}

// 假期
type HoliDay struct{}
func (hd *HoliDay) Do(){
    fmt.Println("出去浪")
}

定义 Context

// 定义 Context 内部嵌套了 Status 
type Context struct {
    Status
}
// 定义方法 SetStatus 用于状态切换
func (ct *Context) SetStatus(status Status){
    c.Status = status
}

使用如下

cont := Context{
    &WorkDay{}
}

cont.Do()
cont.SetStatus(&HoliDay{})
cont.Do()
cont.SetStatus(&WorkDay{})
cont.Do()
原文地址:https://www.cnblogs.com/shangmo/p/14828279.html