前言
状态模式中的行为是由状态来决定的,不同的状态下有不同的行为。状态模式和策略模式的结构几乎完全一样,但他们的目的、本质却完全不同。状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立、可相互替换的。用一句话来表述,状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部改变的时候,其行为也随之改变。
定义
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
使用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。
- 代码中包含大量与对象状态有关的条件语句,例如,一个操作中含有庞大的多分支语句(if-else或switch-case),且这些分支依赖于该对象的状态。
简单案例
下面我们就以电视遥控器为例来演示一下状态模式的实现。我们首先将电视的状态简单分为开机状态和关机状态,在开机状态下可以通过遥控器进行频道切换、调整音量等操作,但是,此时重复按开机键是无效的;而在关机状态下,频道切换、调整音量、关机都是无效的操作,只有按开机按钮时会生效。也就是说电视的内部状态决定了遥控器的行为。
- 定义电视状态接口,定义电视操作的函数
public interface TvState {
public void nextChannel();
public void prevChannel();
public void turnUp();
public void turnDown();
}
- 电视关机状态
public class PowerOffState implements TvState {
@Override
public void nextChannel() {
}
@Override
public void prevChannel() {
}
@Override
public void turnUp() {
}
@Override
public void turnDown() {
}
}
- 电视开机状态
public class PowerOnState implements TvState {
@Override
public void nextChannel() {
System.out.println("下个频道");
}
@Override
public void prevChannel() {
System.out.println("上个频道");
}
@Override
public void turnUp() {
System.out.println("调高音量");
}
@Override
public void turnDown() {
System.out.println("调低音量");
}
}
- 定义电源操作接口
public interface PowerController {
public void powerOn();
public void powerOff();
}
- 实现电视遥控器
public class TvController implements PowerController {
TvState mTvState;
public void setTvState(TvState mTvState) {
this.mTvState = mTvState;
}
@Override
public void powerOn() {
setTvState(new PowerOnState());
System.out.println("开机啦");
}
@Override
public void powerOff() {
setTvState(new PowerOffState());
System.out.println("关机啦");
}
public void nextChannel() {
mTvState.nextChannel();
}
public void prevChannel() {
mTvState.prevChannel();
}
public void turnUp() {
mTvState.turnUp();
}
public void turnDown() {
mTvState.turnDown();
}
}
- 客户端调用代码
public class Client{
public static void main(String[] args) {
TvController tvController = new TvController();
// 设置开机状态
tvController.powerOn();
// 下一频道
tvController.nextChannel();
// 调高音量
tvController.turnUp();
// 设置关机状态
tvController.powerOff();
// 调高音量, 此时不会生效
tvController.turnUp();
}
}
上述实现中,我们抽象了一个TvState接口,该接口中有操作电视的所有函数,该接口有两个实现类,即开机状态(PowerOnState)和关机状态(PowerOffState)。开机状态下只有开机功能是无效的,也就是说在已经开机的时候用户再按开机键不会产生任何反应;而在关机状态下,只有开机功能是可用的,其他功能都不会生效。同一个操作,如调高音量的turnUp函数,在关机状态下无效,在开机状态下就会将电视的音量调高,也就是说电视的内部状态影响了电视遥控器的行为。状态模式将这些行为封装到状态类中,在进行操作时将这些功能转发给状态对象,不同的状态有不同的实现,这样就通过多态的形式去除了重复、杂乱的if-else语句,这也正是状态模式的精髓所在。
总结
状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的一个具体示例。在if-else或者switch-case形式下根据不同的状态进行判断,如果是状态A那么执行方法A、状态B执行方法B,但这种实现使得逻辑耦合在一起,易于出错,通过状态模式能够很好地消除这类“丑陋”的逻辑处理,当然并不是任何出现if-else的地方都应该通过状态模式重构,模式的运用一定要考虑所处的情景以及你要解决的问题,只有符合特定的场景才建议使用对应的模式。
网友评论