定义
状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
结构
- Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时它是一个State的子类对象。
- State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对象的方法,而在其子类中实现了这些方法,由于不同状态下对象的行为可能不同,因此在不同的子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
- ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类的行为有所不同。
代码
State
public abstract class State {
// 抽象业务方法,不同的具体状态可以有不同的实现
public abstract void handle();
}
ConcreteState1
public class ConcreteState1 extends State {
@Override
public void handle() {
System.out.println("ConcreteState1");
}
}
ConcreteState2
public class ConcreteState2 extends State {
@Override
public void handle() {
System.out.println("ConcreteState2");
}
}
Context
public class Context {
// 其他属性,该属性值变化可能回导致对象的状态发生改变
private int value;
// 维持一个对抽象状态的引用
private State state;
public void request() {
// 调用状态对象的业务方法
state.handle();
}
// 统一由环境类来负责状态之间的转换
public void changeState() {
// 判断属性值,根据属性值进行状态转换
if (value == 0) {
setState(new ConcreteState1());
} else if (value == 1) {
setState(new ConcreteState2());
}
}
public void setState(State state) {
this.state = state;
}
}
优/缺点与适用环境
- 优点
- 状态模式封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
- 状态模式将所有与某个状态有关的行为放到一个类中,只需要注人一个不同的状态对象即可使环境对象拥有不同的行为。
- 状态模式允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以避免使用庞大的条件语句将业务方法和状态转换代码交织在一起。
- 状态模式可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
- 缺点
- 状态模式会增加系统中类和对象的个数,导致系统运行开销增大。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。
- 状态模式对开闭原则的支持并不太好,增加新的状态类需要修改那些负责状态转换的源代码,否则无法转换到新增状态,而且修改某个状态类的行为也需要修改对应类的源代码。
- 适用环境
- 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化。
- 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。