目录
- 使用场景
- 参与者
- 协作
- 效果
- 实现
- 相关模式
- 实际应用和思考
状态(State)(对象行为模式)允许一个对象在内部状态改变时改变他的行为。对象看起来似乎修改了他的类
使用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示;通常有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象不依赖于其他对象而独立变化
参与者
- Context
- 定义用户感兴趣的接口
- 维护一个ConcreteState子类的实例,这个实例定义当前状态
- State:定义一个接口以封装与Context的一个特定状态相关的行为
- ConcreteState subclasses:每一个子类实现一个与Context的一个状态相关的行为
协作
- Context将与状态相关的请求委托给当前的ConcreteState对象处理
- Context可将自身作为一个参数传递给处理该请求的状态对象,这使得状态对象在必要时可访问Context
- Context是用户使用的主要接口,客户可用状态对象来配置一个Context,一旦一个Context配置完毕它的客户不再需要直接与状态对象打交道
- Context或ConcreteState子类都可以决定哪一个状态是另外哪个的后继者,以及在何种条件下进行状态转换
效果
- 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来,所以通过定义新的子类可以很容易的增加新的状态和转换,说白了这样做的目的就是为了消除庞大的条件语句(但子类中不可避免的还是出现了条件语句?),状态模式通过把各种状态转移逻辑分布到state的子类之间,来减少相互间的依赖。
- 使得状态转换显式化:当一个对象仅以内部数据值来定义当前状态时其状态仅表现为对一些变量的赋值,不够明确,为不同的状态引入独立的对象使得转换变得更加明确。
- State对象可被共享
- 将不同的状态分布在多个state中增加了子类的数目,相对于单个类的实现来说不够紧凑,但避免了巨大的条件语句
实现
- 谁定义状态转换:State模式不指定哪一个参与者定义状态转换准则,如果该准则是固定的,可以在Context中实现。然而如果让State子类自身指定他们的后继状态以及何时进行转换会更加灵活,这需要Context增加一个接口让State对象显式的设定Context的当前状态(能不能做到自动转换状态,对Context而言没有感知?)。但为了保证状态改变对外关闭,需要将state类设置为友元
- 优点:用这种方法分散转换逻辑可以很容易地定义新的state子类来修改和扩展该逻辑
- 缺点:一个state子类至少拥有一个其他子类的信息,这就在各子类之间产生了实现依赖;并且子类之间很可能是按顺序依赖的,意味着每个状态的下一个状态是什么是固定的——这些依赖的状态的管理是Context还是上一个State?
- 基于表的另一个方法:将条件代码映射为一个查找表:怎么实现?
- 创建和销毁State对象
- 仅当需要state对象时才创建它们并随后销毁它们:当将要进入的状态在运行时不可知,且上下文不经常改变时
- 提前创建并且始终不销毁:当状态改变很频繁时
- 使用动态继承
相关模式
- 享元模式解释了何时以及怎样共享状态对象——?
- 状态通常是单例
实际应用和思考
- 状态机与状态模式的区别与联系
- Context的哪些与状态相关的行为需要在状态类中实现?目前的两个例子似乎都没有体现出来
- 从目前看,庞大的条件分支只是分发给各个具体的状态类了,并没有消除掉,是哪里的问题?
- 状态关联的行为由Context去调用还是状态自身调用,如果是状态自身怎么使用,如果是Context调用,那和普通的封装就没有区别了?
(Context到State的连线意味着State可以离开Context而单独存在)