前言
- 状态模式跟策略模式跟相似,从他们两个UML类图中就可以看出.
- 状态模式其实就是一个将if-else用多态来实例的一个具体示例.
定义
- 定义:当一个对象的类在状态改变时允许改变其行为,这个对象看起来像是改变了其类.
- 使用场景:
1.一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为.
2.代码中包含大量与状态有关的if-else语句,并且它必须是在运行时根据状态的改变改变它的行为.其实有点类似:自定义listview下拉刷新时,动态的去改变headview的图片和文字,其实也就是几个状态根据高度的切换 - 作用:通过多态来去除过多的,重复的if-else等分支语句
- 优点:状态模式将所有与一个特定的状态相关的行为都放入一个状态对象中,它提供了一个更好的方法来组织和特定状态相关的代码,将烦琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性和可维护性.
- 缺点:状态模式的使用必然会增加系统类和对象的个数.
UML类图

- context:上下文,跟state一对多的关系
- state: 抽象状态类或者状态接口,表示该状态下的行为
- ConcreteSateA:具体状态类,实现state接口
实现步骤
- 案例:这里是直接模拟书上提供的案例,模拟电视开关机下的状态操作
- 接下来是我们的demo目录截图 :

- 我们先来看看,很容易就常规的写法,作为对比,常规的if-else操作,把电视遥控器的相关行为全部归纳到TvController这个类里面:
- 如果是有新的需求需要在该类进行修改和维护,是不是很麻烦了,有可能会动到以前正常的代码,这是不是又违反了代码设计模式的开闭原则呢?
/**
* 常规代码if-else实现遥控器功能
* @author max
*
*/
public class TvController {
private final static int POWER_ON = 1;
private final static int POWER_OFF = 2;
private int mState = POWER_OFF;
public void powerOn(){
mState = POWER_ON;
if (mState == POWER_ON) {
System.out.println("开机了");
}
}
public void powerOff(){
mState = POWER_OFF;
if (mState == POWER_OFF) {
System.out.println("关机了");
}
}
public void nextChannel(){
if (mState == POWER_ON) {
System.out.println("下一个频道");
}else{
System.out.println("没有开机");
}
}
public void prevChannel(){
if (mState == POWER_ON) {
System.out.println("上一个频道");
}else{
System.out.println("没有开机");
}
}
public void turnUp(){
if (mState == POWER_ON) {
System.out.println("调高音量");
}else{
System.out.println("没有开机");
}
}
public void turnOff(){
if (mState == POWER_ON) {
System.out.println("降低音量");
}else{
System.out.println("没有开机");
}
}
}
- 在让我们来看看状态模式的实现,虽然类很多,但是思路和清晰明了.对于后期的维护只需要在接口里面实现对应新的方法即可.这里我们来看看状态模式的具体实现步骤吧
- TvState:遥控器的功能接口,新业务直接在这里新增方法
/**
* 电视状态接口--定义电视操作的函数
* @author max
* */
public interface TvState {
public void nextChannel();
public void prevChannel();
public void turnUp();
public void turnOff();
}
- PowerController:电源操作接口,也就是开机和关机的两个状态,有新的状态在这里新增方法
/**
* 电源操作接口--开机关机
* @author max
* */
public interface PowerController {
public void powerOn();
public void powerOff();
}
- PowerOnState和PowerOffState这两个类主要是实现对应状态下TvState的业务方法:这里不贴代码了,有兴趣的同学下源码来看吧
- TvControllerInState:这个类主要实现PowerController这个接口的方法,并提供对外设定状态和相关业务的方法,有点类似于builder模式的builder类.这里贴代码给大家看下
/**
* 状态模式来实现开关机
* @author max
*
*/
public class TvControllerInState implements PowerController {
TvState mTvState;
/**
* 对外方法,设置状态
* @param mTvState
*/
public void setmTvState(TvState mTvState) {
this.mTvState = mTvState;
}
@Override
public void powerOn() {
System.out.println("开机了");
}
@Override
public void powerOff() {
System.out.println("关机了");
}
/**
* 定义跟TvState接口一样的方法,返回
*/
public void nextChannel() {
mTvState.nextChannel();
}
public void prevChannel() {
mTvState.prevChannel();
}
public void turnUp() {
mTvState.turnUp();
}
public void turnOff() {
mTvState.turnOff();
}
}
- 当然最后是我们在调用这两种写法的代码,其优缺点大家也就一目了然了:
/**
* 状态模式实现
*/
private void stateMethod() {
TvControllerInState state = new TvControllerInState();
state.powerOn();
state.nextChannel();
state.prevChannel();
state.turnUp();
state.turnOff();
}
/**
* 原始if-else实现
*/
private void initailMethod() {
TvController controller = new TvController();
controller.powerOn();
controller.prevChannel();
controller.powerOff();
}
源码下载