一,动机
当一个对象的状态发生改变时,有时候我们会希望它的行为也会随着状态的改变而改变。
比如一个人(对象),没钱的时候(状态)晚上只能吃泡面(行为),但是当他有钱了(状态发生改变),那么他就可以大口吃肉了(行为也发生改变)。
这个时候就需要一种方式,在对象的状态发生改变的时候也同样改变它的行为。
State模式就是这样一种模式,允许一个对象在它的内部状态发生改变的时候也改变它的行为,因为行为方法变得不同了,就好像这个类也发生了改变一样。
二,介绍
1.参与者
Context 环境,上下文,定义了用户需要调用的方法,并且维护了ConcreteState的实例,该实例定义了Context的状态。
State 状态,抽象的状态类,用接口定义一个Context在某种状态下的行为。
ConcreteState 具体的状态实现类,实现一个与Context状态相关的行为。
2.协作关系
Context 将与状态有关的请求委托给ConcreteState来处理。
Context 可以将自身作为一个参数传给处理该请求的 ConcreteState 对象。
Context 是主要的用户入口,用户只需与Context打交道,而无需考虑 ConcreteState 。
Context 和 ConcreteState 都可以决定哪个状态是另一个状态的后继状态,以及在什么条件下进行状态转换。
代码示例
public interface State{
public void eat();
}
public class PoorState implements State{
public void eat() {
System.out.println("吃泡面");
}
}
public class RichState implements State{
public void eat() {
System.out.println("吃山珍海味");
}
}
public class Person {
State state;
public void setState(State state){
this.state = state;
}
public void eat(){
this.state.eat();
}
}
三,使用场景
对象的行为取决于自身的状态,并且需要在运行时根据自身的状态来决定自己的行为。
当一个操作包含多个条件分支,并且这些分支的条件判断都取决于对象的状态时,可以使用state模式将分支放入类中,使得对象根据状态的不同调用不同的方法。
四,效果
1.将与状态有关的行为局部化,将不同状态的行为分割开。
State模式将所有与某个状态有关的行为都放到一个子类中,因此可以轻松的通过定义新的子类来追加新的状态和转换。对于一般的通过if...else...等条件语句来控制对象的行为,会导致在状态很多的情况下,出现大量的条件分支,从而使整个代码变得庞大,也更难阅读和维护。增加一个新的状态可能会导致要改变多个操作。
State 模式解决了这些问题,将不同状态的行为放到不同的子类中,从而减少了分支。但于此同时,为不同的状态创建不同的子类,也会导致子类的数目变多,而对于单个类中的代码不够紧凑,出现类的数量很多,但是每个类里的代码逻辑却很少的情况。
2.使状态转换显式化
如果一个对象仅通过内部的属性来定义状态的话,那么状态的转换仅表现为变量的赋值,不够明确,容易发生状态不一致的情况。比如,一个属性记录这个人是有钱的,另一个属性却记录了这个人只有1元钱,就会出现状态不一致的情况:有钱,却只有1元钱。
使用State模式可以避免这个情况发生,因为对于Context而言,状态的转换是原子的,需要为重新绑定State变量。