状态模式
状态模式(Strategy Pattern)又名状态对象(Objects for States)
意图
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
使用场景
当出现下面的两种情况之一时使用State模式
- 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
结构
状态模式结构如下
Context
– 定义Client所关注的接口。
– 维护一个ConcreteState子类的实例,这个实例定义当前状态。State
– 定义一个接口以封装与Context的一个特定状态相关的行为。ConcreteState subclasses
– 每一子类实现一个与Context的一个状态相关的行为。
协作
- Context将与状态相关的请求委托给当前的ConcreteState对象处理。
- Context可将自身作为一个参数传递给处理该请求的状态对象。这使得状态对象在必要时可访问Context。
- Context是客户使用的主要接口。客户可用状态对象来配置一个Context,一旦一个Context配置完毕, 它的Client不再需要直接与状态对象打交道。
- Context或ConcreteState子类都可决定哪个状态是另外哪一个的后继者,以及是在何种条件下进行状态转换。
效果
State模式有下面一些效果
- 它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
– State模式将所有与一个特定的状态相关的行为都放入一个对象中。因为所有与状态相关的代码都存在于某一个State子类中, 所以通过定义新的子类可以很容易的增加新的状态和转换。
– State模式避免使用大量的ifelse语句或者switchcase语句来控制状态,但是可能会引入更多的类,增加了子类的数目 - 它使得状态转换显式化
– 当一个对象仅以内部数据值来定义当前状态时, 其状态仅表现为对一些变量的赋值,这不够明确。为不同的状态引入独立的对象使得转换变得更加明确。而且, State对象可保证Context不会发生内部状态不一致的情况,因为从Context的角度看,状态转换是原子的–只需重新绑定一个变量(即Context的State对象变量),而无需为多个变量赋值。 - State对象可被共享
– 如果State对象没有实例变量–即它们表示的状态完全以它们的类型来编码–那么各Context对象可以共享一个State对象。当状态以这种方式被共享时, 它们必然是没有内部状态, 只有行为的轻量级对象(Flyweight Pattern)。
状态模式实现(Implement)
案例
F1比赛大家应该都看过,作为世界上最烧钱的比赛,一辆车就动辄几百万。F1赛车的变速箱也非常特别,赛车手只需要拨动方向盘上的拨片就可以进行换挡,看上去十分酷炫。现在用代码来实现这个换挡过程。
代码实现
先来看下面一段代码
代码之中充斥着大量的条件语句,看上去非常的不舒服。现在引入状态模式对原来结构进行调整。
将状态抽象出来
新的变速器类,Client只需要调用upShift操作和downShift操作就可以了,具体的状态交给GearState去处理。
每个档位都抽成一个类并且继承GearState抽象类,代码太多,这里只选择空挡和一档进行展示
|
|
这么一修改,代码的结构看上去整洁了许多了,而且扩展性也变好了。
总结
状态模式帮助我们更简单的控制对象的状态,结构变得更加简单易读了。状态模式和策略模式的结构看上去非常的相似,但是他们之间还是有区别的,策略模式的目的是为了通过不同的方法去完成一件事,而状态模式不一样,状态模式会根据当前的状态做出选择,比如开关灯的操作,用开关去操作时会去判断当前的开关状态再操作,如果灯关了就打开它,灯开了就关闭它。这也是GoF那本书里面讲的意图,在内部状态改变时改变自身的行为。