状态模式定义:(对象行为型模式)允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态模式主要解决了当控制一个对象状态表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,将复杂逻辑进行简化。
2 目标问题
在网络连接的过程中,可以使用一个 TCPConnect 对象进行管理,这个对象可能处于多种状态之间:正在监听、连接已经建立、连接关闭等等。当一个 TCPConnect 对象收到其他对象的请求时,它根据自身的当前状态做出不同的反应。使用 State 模式描述 TCPConnect 如何在每一种状态下表现出不同的行为。
3 解决方法
引入一个 TCPState 抽象类来表示网络的连接状态。TCPState 类为各个表示不同状态的操作提供了一套相同的公共接口。TCPState 的子类实现与特定状态相关的行为。例如连接关闭对应的类为 TCPClosed。
TCPConnect 对象通过维护一个实现了 TCPState 接口用来表示 TCP 连接状态的状态对象,并将所有和状态相关的操作交给这个状态对象进行处理即可。当 TCPConnect 的状态改变时,将这个状态对象进行替换即可。
4 所有类之间的关系
- Context 类:eg:TCPConnect
- 定义客户感兴趣的接口
- 维护一个 ConcreteState 子类的实例,这个实例定义当前的状态
- State 接口:
- 所有对应的状态子类实现的接口,用来执行 Context 类在对应状态的操作
- ConcreteState 类:可以有多个:TCPClosed、TCPListen、TCPEstablished
- 每一个子类实现 Context 类在对应状态下的操作
- 当 Context 状态改变时,首先创建一个新的状态对象,并将其替换掉 Context 中的对象即可
5 代码实现
下面展示了一个日历的例子,例子来源见本文最后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
type Day interface { Today() Next(*DayContext) }
type DayContext struct { today Day }
func () *DayContext { return &DayContext{ today: &Sunday{}, } }
func (d *DayContext) Today() { d.today.Today() }
func (d *DayContext) Next() { d.today.Next(d) }
type Sunday struct{}
func (*Sunday) Today() { fmt.Printf("Today is Sundayn") }
func (*Sunday) Next(ctx *DayContext) { ctx.today = &Monday{} }
type Monday struct{}
func (*Monday) Today() { fmt.Printf("Today is Mondayn") }
func (*Monday) Next(ctx *DayContext) { ctx.today = &Tuesday{} }
type Tuesday struct{}
func (*Tuesday) Today() { fmt.Printf("Today is Tuesdayn") }
func (*Tuesday) Next(ctx *DayContext) { ctx.today = &Wednesday{} }
type Wednesday struct{}
func (*Wednesday) Today() { fmt.Printf("Today is Wednesdayn") }
func (*Wednesday) Next(ctx *DayContext) { ctx.today = &Thursday{} }
type Thursday struct{}
func (*Thursday) Today() { fmt.Printf("Today is Thursdayn") }
func (*Thursday) Next(ctx *DayContext) { ctx.today = &Friday{} }
type Friday struct{}
func (*Friday) Today() { fmt.Printf("Today is Fridayn") }
func (*Friday) Next(ctx *DayContext) { ctx.today = &Saturday{} }
type Saturday struct{}
func (*Saturday) Today() { fmt.Printf("Today is Saturdayn") }
func (*Saturday) Next(ctx *DayContext) { ctx.today = &Sunday{} }
func main() { ctx := NewDayContext() todayAndNext := func() { ctx.Today() ctx.Next() }
for i := 0; i < 8; i++ { todayAndNext() } }
|
打印结果如下:
6 应用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为
- 一个操作中含有庞大的分支和条件语句时,这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量进行表示。通常有多个操作包含这一相同条件结构。通过 State 对象将不同分支进行划分,可以不依赖其余的 State 进行变化
7 优缺点
7.1 优点
- 单一责任原则。将与特定状态相关的代码组织到单独的类中
- 开放/封闭原则。在不更改现有状态类或上下文的情况下引入新状态
- 通过消除笨重的状态机条件来简化上下文代码
7.2 缺点
8 相关模式
- Bridge,State,Strategy 具有非常相似的结构。实际上,所有这些模式都是基于构图的,这将工作委托给其他对象。但是,它们解决了不同的问题。
9 reference
《设计模式》-状态模式
design-patterns:state pattern
本小节日历例子
近期评论