1979年在湖北出土的曾侯乙编钟,每一只钟都能发出不同的音。
用面向对象的语言来讲,编钟有能够动态变化的属性,也就是它所能发出的声音。编钟的这种属性叫做状态,而编钟被叫做有状态的对象。编钟所能发出的声音是由敲击的那一只钟决定,而钟的数目个每一只钟的状态是事先确定的。
很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的对象。
状态模式的类图如下:
状态模式设计的角色有:
抽象状态角色(State):定义一个接口,用以封装环境对象的一个特定的状态所对应的行为
具体状态角色(ConcreteState):每一个具体状态类都实现了环境的一个状态所对应的行为。
环境角色(Context):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。
从上图可以看出,环境类Context是所考察的类,而他的行为sampleOperation()是委派给类型为State的一个对象的。由于State本身是一个抽象类或接口,实际担当此任务的是具体的状态类,即:ConcreteState。上图只给出了一个具体的状态类,而实际情况中会有很多具体状态类。换言之,环境类Context的行为SampleOperation()是委派给某一个具体状态类的。
通过使用多态性原则,可以动态的改变环境类Context的属性State的内容,使其从从指向一个具体状态类变换到指向另一个具体的状态类,从而使环境类的行为sampleOperation()由不同的具体状态来执行。
环境角色的源码:
public class Context {
private State state;
public void sampleOperation(){
state.sampleOperation();
}
public void setState(State state){
this.state = state;
}
}
抽象状态接口:
public interface State {
public void sampleOperation();
}
具体状态类:
public class ConcreteState implements State {
public void sampleOperation() {
// do something
}
}
什么情况下使用状态模式
1、一个对象的行为依赖于它所处的状态,对象的行为必须随着其状态的改变而改变
2、对象在某一个方法里依赖于一重或多重的条件转移语句,其中有大量的代码。状态模式把条件转移语句的每一个分支都包装到一个单独的类里。使得这些条件转移分支能够以类的方式独立存在和演化。维护这些独立的类也就不再影响到系统的其他部分。