状态模式(State):当一个对象的内在状态变化时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化。
当然了,如果这个状态判断很简单,那么就没必要使用状态模式了。
状态模式(State)结构图
public abstract class State {
abstract void handle(Context context);
}
// 具体状态A类
public class ConcreteStateA extends State {
@Override
void handle(Context context) {
// 设置下一个状态是B类对象
context.setState(new ConcreteStateB());
}
}
// 具体状态B类
public class ConcreteStateB extends State {
@Override
void handle(Context context) {
// 设置下一个状态是A类对象
context.setState(new ConcreteStateA());
}
}
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
System.out.println("当前状态:" + this.state.getClass().getName());
}
public void request() {
this.state.handle(this);
}
}
Context context = new Context(new ConcreteStateA());
context.request();
context.request();
context.request();
context.request();
例:将工作时的工作状态使用编程方式实现一下:
臃肿实现方式:
static int hour = 0;
static boolean workFinished = false;
static void writeProgram() {
if (hour < 12) {
System.out.println("当前时间:" + hour + "点 上午工作 精神百倍!");
} else if (hour < 13) {
System.out.println("当前时间:" + hour + "点 饿了,去干饭,犯困,午休");
} else if (hour < 17) {
System.out.println("当前时间:" + hour + "点 下午状态还行,继续努力");
} else {
if (workFinished) {
System.out.println("当前时间:" + hour + "点 下班走人");
} else {
if (hour < 21) {
System.out.println("当前时间:" + hour + "点 加班哦,很疲惫");
} else {
System.out.println("当前时间:" + hour + "点 嘎嘎累 要睡着了");
}
}
}
}
hour = 9;
writeProgram();
hour = 11;
writeProgram();
hour = 12;
writeProgram();
hour = 13;
writeProgram();
workFinished = false;
hour = 19;
writeProgram();
那么可以看到,很多状态的切换都是这样子面向过程的方式实现。如何进行封装呢,就使用到了状态模式。
给个结构图
将所有时间段的工作状态都分别封装到一个类中。请看具体实现。
public abstract class State {
abstract void writeProgram(Work w);
}
// 上午工作状态
public class ForenoonState extends State {
@Override
void writeProgram(Work w) {
if (w.getHour() < 12) {
System.out.println("当前时间:" + w.getHour() + "点 上午工作 精神百倍!");
} else {
w.setCurrent(new NoonState());
w.writeProgram();
}
}
}
// 中午工作状态
public class NoonState extends State {
@Override
void writeProgram(Work w) {
if (w.getHour() < 13) {
System.out.println("当前时间:" + w.getHour() + "点 饿了,去干饭,犯困,午休");
} else {
w.setCurrent(new AfternoonState());
w.writeProgram();
}
}
}
// 下午工作状态
public class AfternoonState extends State {
@Override
void writeProgram(Work w) {
if (w.getHour() < 17) {
System.out.println("当前时间:" + w.getHour() + "点 下午状态还行,继续努力");
} else {
w.setCurrent(new EveningState());
w.writeProgram();
}
}
}
// 晚间工作状态
public class EveningState extends State {
@Override
void writeProgram(Work w) {
if (w.isWorkFinished()) {
w.setCurrent(new RestState()); //完成任务下班
w.writeProgram();
} else {
if (w.getHour() < 21) {
System.out.println("当前时间:" + w.getHour() + "点 加班哦,很疲惫");
} else {
w.setCurrent(new SleepingState()); // 转入睡眠工作状态
w.writeProgram();
}
}
}
}
// 睡眠工作状态
public class SleepingState extends State {
@Override
void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 嘎嘎累 要睡着了");
}
}
// 下班
public class RestState extends State {
@Override
void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 下班走人");
}
}
Work w = new Work();
w.setHour(10);
w.writeProgram();
w.setHour(12);
w.writeProgram();
w.setHour(15);
w.writeProgram();
w.setHour(17);
w.writeProgram();
w.setWorkFinished(false);
w.setHour(19);
w.writeProgram();
w.setHour(22);
w.writeProgram();
好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开。
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存放在于某个ConcreteState类中,所以通过定义新的子类可以很容易增加新的状态和转换。
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就需要考虑使用状态模式了了。