状态模式,将条件的判断从业务逻辑中分离出去,或者说将状态的转换规则分离出去。
程序运行中所依赖的条件可视作程序的状态,程序的运行逻辑非常复杂,在不同的状态下需要有不同的表现,甚至某状态的作用要依赖另外的状态,状态模式将程序“状态”(即程序运行条件)进行了抽象,这样,通过自由切换状态条件可以方便地得到不同的表现。
我们在程序设计过程中,经常会涉及到在某些状态下进行特定的操作,一般我们会传入一个条件,然后对条件进行判断,如果是...则...,通常都会首先想到if..else..的编码方式,这种if...else的思维方式不符合面向对象的思维方式,因为这种思维是面向过程的!
这种方式的缺点很明显:
1.如果有新条件的加入则需要修改主逻辑,添加新的if..else,不符合开闭原则。
2.如果状态间有依赖关系,比如先后顺序,不容易体现和维护。
如果你的代码中出现了大片的 if ..else 那么就应该考虑使用 状态模式了,如过我们需要根据某某的状态进行操作,当它是什么的时候我们进行某某操作..我们还需要状态可以切换的,可以回退到上个状态,我们还希望能在这个状态进行完乎自动切到下个状态工作,它们的顺序是需要保证的等等,那么就应该考虑使用 状态模式了。
如果我们的程序要适应复杂的“状态变化”,那么就要使用状态模式了。
状态模式把 状态的变化规则 从业务逻辑中抽取出来,从而可以方便地改变状态,进而驱动不同的业务逻辑。
状态模式的实现通常会有一个“状态管理器”,用于管理既有状态以及将状态转换到原有业务逻辑中去。
转换规则可以在具体的状态中或状态管理器中来实现,从而与原有业务逻辑相分离。
场景:电视机在不同的频道下播放不同的节目,且我们假设老式的电视频道只能往前或往后顺序选择,不能随意选频道(即频道之间有依赖关系),根据不同的频道电视机通过查找、接收、处理等复杂的逻辑将节目播放出来。
设计:

示例代码:
interface ChannelState {
String show();
void push(ChannelStateContext ctx);
void pull(ChannelStateContext ctx);
}
class ChannelStateContext {
ChannelState currentState;
ChannelStateContext(ChannelState channelState) {
this.currentState = channelState;
}
void changeToNext() {
currentState.push(this);
}
void changeToLast() {
currentState.pull(this);
}
void setChannelState(ChannelState state) {
currentState = state;
}
String action() {
StringBuilder result = new StringBuilder("===查找信号,接收信号,处理信号... 播放节目:");// TODO 调用其它业务逻辑
result.append(currentState.show());//调用当前状态
return result.toString();
}
}
class MovieChannel implements ChannelState {
public String show() {
return "电影";
}
public void push(ChannelStateContext ctx) {
ctx.setChannelState(new MusicChannel());
}
public void pull(ChannelStateContext ctx) {
ctx.setChannelState(new OtherChannel());
}
}
class MusicChannel implements ChannelState {
public String show() {
return "音乐";
}
public void push(ChannelStateContext ctx) {
ctx.setChannelState(new OtherChannel());
}
public void pull(ChannelStateContext ctx) {
ctx.setChannelState(new MovieChannel());
}
}
class OtherChannel implements ChannelState {
public String show() {
return "其它";
}
public void push(ChannelStateContext ctx) {
ctx.setChannelState(new MovieChannel());
}
public void pull(ChannelStateContext ctx) {
ctx.setChannelState(new MusicChannel());
}
}
public class Test {
public static void main(String[] args) {
// 初始状态为电影,也可以是其它其它状态
ChannelStateContext channelStateContext = new ChannelStateContext(new MovieChannel());// 电影
System.out.println(channelStateContext.action());
// 向后切换
channelStateContext.changeToNext();// 音乐
System.out.println(channelStateContext.action());
channelStateContext.changeToNext();// 其它
System.out.println(channelStateContext.action());
channelStateContext.changeToNext();// 电影
System.out.println(channelStateContext.action());
// 向前切换
channelStateContext.changeToLast();// 其它
System.out.println(channelStateContext.action());
channelStateContext.changeToLast();// 音乐
System.out.println(channelStateContext.action());
channelStateContext.changeToLast();// 电影
System.out.println(channelStateContext.action());
}
}
输出:
===查找信号,接收信号,处理信号... 播放节目:电影
===查找信号,接收信号,处理信号... 播放节目:音乐
===查找信号,接收信号,处理信号... 播放节目:其它
===查找信号,接收信号,处理信号... 播放节目:电影
===查找信号,接收信号,处理信号... 播放节目:其它
===查找信号,接收信号,处理信号... 播放节目:音乐
===查找信号,接收信号,处理信号... 播放节目:电影
状态模式与策略模式的区别,参见:策略模式。