介绍
- 其行为由状态决定,不同状态下有不同的行为。
- 状态模式下的行为是平行的、不可替换的(策略模式的行为是彼此独立、可以替换的)
- 状态模式下,不同的状态对象(注意是状态对象)拥有一个抽象的状态基类
定义
当一个状态的内在状态发生变化允许改变其行为,这个对象看起来像是改变了其类(多态)
使用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变他的行为
- 代码中包含大量和状态相关的条件语句,且这些分之语句依赖于该对象的状态
- 状态模式将每个条件分之放入一个独立的类中,使得我们可以根据对象自身的状态情况作为一个对象,这个对象不依赖其他对象而独立存在,通过多态去除重复的,过多的if-else等分之语句
UML类图
说明
- Context:环境类,实现客户端感兴趣的方法,维护一个State实例对象,State对象定义了当前的状态,通过State对象的多态特性,自动调用其状态下该有的方法
- State:抽象状态基类或者状态接口,定义一些方法或者接口,便是状态下应有的行为
- ConcreteStateA、ConcreteStateB:具体状态类,每个具体状态下实现抽象类Stat中定义的方法或者接口,实现不同状态下的不同行为
具体实现
我们都知道电视在开机状态下可以实现调节频道,调节音量等操作;在关机状态下只能开机操作,而频道和音量调节都不能实现。下面我们就对这种应用场景实现其具体代码:
- TvState
TvStat类中定义了操作电视的共有方法,不同状态下应有其具体实现类/** * 电视操作基类 */ public interface TvState { //下一个频道 void nextChannel(); //上一个频道 void prevChannel(); //增加音量 void turnUp(); //减小音量 void turnDown(); }
PowerOffState
/** * 关机状态下的逻辑 */ public class PowerOffState implements TvState { @Override public void nextChannel() { System.out.println("PowerOffState->nextChannel"); } @Override public void prevChannel() { System.out.println("PowerOffState->prevChannel"); } @Override public void turnUp() { System.out.println("PowerOffState->turnUp"); } @Override public void turnDown() { System.out.println("PowerOffState->turnDown"); } }
关机状态下的具体实现,此状态下电视的频道和音调节量都不能操作
PowerOnState
/** * 开机状态下的操作逻辑实现类 */ public class PowerOnState implements TvState { @Override public void nextChannel() { System.out.println("PowerOnState->nextChannal"); } @Override public void prevChannel() { System.out.println("PowerOnState->prevChannel"); } @Override public void turnUp() { System.out.println("PowerOnState->turnUp"); } @Override public void turnDown() { System.out.println("PowerOnState->turnUp"); } }
开机状态下的具体实现,能够正常的对电视进行频道和音量的调节操作
PowerController
/** * 电源控制接口 */ public interface PowerController { //开机 void powerOn(); //关机 void powerOff(); }
电源控制类,TvState的具体实现类中的具体行为就是因电源状态发生改变而改变的。
TVController
/** * 电视控制类,实现电源接口 * 内部保留TvState对象,实现电视具体的逻辑操作 */ public class TvController implements PowerController { //保留TvState实例对象,调用其对应状态下的对象方法 private TvState mTvState; private void setTvState(TvState state){ mTvState = state; } @Override public void powerOn() { setTvState(new PowerOnState()); System.out.println("TV->powerOn"); } @Override public void powerOff() { setTvState(new PowerOffState()); System.out.println("TV->powerOff"); } /** *以下各种操作电视的逻辑分别是在对应电视开关机状态下逻辑实现 */ public void nextChannel(){ mTvState.nextChannel(); } public void prevChannel(){ mTvState.prevChannel(); } public void turnUp(){ mTvState.turnUp(); } public void turnDown(){ mTvState.turnDown(); } }
TVController对应于Context类,实现PowerController的方法(开机和关机),通过开关机我们得知其具体的状态,在这种状态下,通过具体行为的基类TvState实例对象,应用多态特性,其对象的具体行为自动接受其状态牵制,达到不同状态下有不同的具体行为
运行结果
TV->powerOff PowerOffState->nextChannel PowerOffState->turnUp TV->powerOn PowerOnState->prevChannel PowerOnState->turnUp
上面的实例中
- 我们抽象一个TvState接口,该接口中有操作电视的所有方法,其对应有两个实现类PowerOffState和PowerOnState
- 开机状态下用户可以对电视进行频道和音量的调节操作,关机状态却不能。这里就侧面反映了电视电源的状态影响了其具体的行为
- 状态模式就是将这些行为封装在一个对象状态类中,在进行操作时将这些功能转发到状态对象,导致不同状态下有不同的行为
总结
优点
- 封装了转换规则,状态类对象持有不同状态下的相应行为,达到不同状态下拥有不同的行为
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 将复杂的状态判断转换成结构清晰的状态类,保证好的扩展性和可维护性
缺点
- 状态类的使用必然会增加系统类和对象的个数
- 应用场景的状态模式功能划分相对复杂,如果使用不当将导致程序结构和代码的混乱