状态模式(State Pattern)

状态模式(State Pattern)


状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。


看个例子

写一个糖果机的系统,糖果机有4种状态,如下:

在这里插入图片描述

  1. 没有1块

  2. 有1块

  3. 售出糖果

  4. 糖果售罄

const (
    SOLD_OUT = 0;
	NO_ONEYUAN = 1;
    HAS_ONEYUAN = 2;
    SOLD = 3;
)

type SugarMachine struct{
    state int
    count int
}

func InitSugarMachine(count int) SugarMachine{
    state = SOLD_OUT
    if count > 0 {
        state = NO_ONEYUAN
    }
    return &SugarMachine{
        state : state.
        count : count,
    }
}

func (s *SugarMachine) insertOneYuan() {
    if s.state == HAS_ONEYUAN {
        fmt.Println("已经投了1元了")
    } else if s.state == NO_ONEYUAN {
        state = HAS_ONEYUAN
        fmt.Println("投入1元")
    } else if s.state == SOLD_OUT {
        fmt.Println("不能投钱,糖果已售完")
    } else if s.state == SOLD {
        fmt.Println("稍等,糖果正在出货")
    }
}

func (s *SugarMachine) ejectOneYuan() {
    if s.state == HAS_ONEYUAN {
        state = NO_ONEYUAN
        fmt.Println("正在退钱")
    } else if s.state == NO_ONEYUAN {
        fmt.Println("没有投入的钱")
    } else if s.state == SOLD_OUT {
        fmt.Println("不能退钱,因为你还没有投钱")
    } else if s.state == SOLD {
        fmt.Println("已经售出,不能退钱")
    }
}

func (s *SugarMachine) turnCrank() {
    if s.state == HAS_ONEYUAN {
        s.state = SOLD
        dispense()
        fmt.Println("正在出货")
    } else if state == NO_ONEYUAN {
        fmt.Println("请先投钱")
    } else if state == SOLD_OUT {
        fmt.Println("抱歉,没有糖果了")
    } else if state == SOLD {
        fmt.Println("已经转过了")
    }
}

func (s *SugarMachine) dispense() {
    if state == HAS_ONEYUAN {
        fmt.Println("发生错误")
    } else if state == NO_ONEYUAN {
        fmt.Println("请先付钱")
    } else if state == SOLD_OUT {
        fmt.Println("发生错误")
    } else if s.state == SOLD {
        fmt.Println("糖果正在滚出")
        s.count = s.count - 1
        if s.count == 0 {
            s.state = SOLD_OUT
        } else {
            s.state = NO_ONEYUAN
        }
    }
}

以上是糖果机的代码,我们实现了所有动作在不同状态下的行为。但上面的代码是一份好的代码吗?

如果我们现在想多加一个状态会怎么样呢?我们首先多定义一个状态的值,然后在每个操作最后再多加一个else来出来这个新状态的行为。

上述代码出现的问题:

· 没有遵守开放-关闭原则

· 状态切换隐藏在条件语句中,所以不是很明显

· 没有把会改变的地方包起来

· 新加入的代码可能会对之前的逻辑引来新的bug


认识状态模式

状态决定行为

所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,行为大多可以对应到方法上。

状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。

由于状态是在运行期间被改变的,因此行为也会在运行期间根据状态的改变而改变,看起来,同一个对象,在不同的运行时刻,行为也是不一样的,就像是类被修改了一样。

从上面的例子可以看出,我们需要把状态和状态对应的行为从原来的代码中分离出来,把每个状态所对应的功能处理封装在一个独立的类里,这样选择不同处理的时候,其实就是在选择不同的状态处理类。

状态模式类图

在这里插入图片描述

· Context:上下文,通常用来定义客户感兴趣的接口。上下文是持有状态的对象,但是上下文自身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理;

· State:状态接口,用来封装与上下文的一个特定状态所对应的行为;

· ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。

如果没有上下文,那么就退化回到只有接口和实现了,正式通过接口,把状态和状态对应的行为分开,才使得通过状态模式设计的程序易于扩展和维护。


与策略模式的区别

这两个模式从模式结构上看是一样的,但是实现的功能或意图是不一样的。

状态模式是根据状态的变化来选择相应的行为,不同的状态对应不同的类,每个状态对一个对应的类实现了该状态对应的功能,在实现功能的同时,还会维护状态数据的变化。这些实现状态对应的功能类之间是不能相互替换的。策略模式是根据需要或者是客户端的要求来选择想要的实现类,各个实现类是平等的,是可以相互替换的。

策略模式可以让客户端来选择需要使用的策略算法;而状态模式一般是由上下文,或者是在状态实现类里面来维护具体的状态数据,通常不由客户端来指定状态。

在这里插入图片描述


优点

· 简化应用逻辑控制
状态模式使用单独的类类封装一个状态的处理。如果把一个大的程序控制分成很多小块,每个定义一个状态代表,那么就可以把这些逻辑控制的代码分散到很多单独的状态中去,这样就把着眼点从执行状态提高到整个对象的的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制

· 更好地分离状态和行为

· 更好的扩展性

· 显式化进行状态转换
状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。


代码范例

代码:https://github.com/zxmfke/tech_learning_NoteOrBook/edit/master/design_pattern/state_pattern/example

范例代码就是用状态模式实现例子的代码

有一个变量来记录状态对象,只要为这一个变量赋值就可以了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值