1 概述
状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
- 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
2 好处与用法
-
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
-
将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。
-
目的是为了消除庞大的条件分支语句。
-
状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。
-
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。
3 示例
抽象状态类,定义一个抽象方法“写程序”。
public abstract class State {
public abstract void writeProgram(Work w);
}
上午和中午工作状态类。
public class ForenoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 12) {
System.out.println("当前时间:" + w.getHour() + "点 精神百倍");
} else {
// 超过12点,则转入中午工作状态
w.setState(new NoonState());
w.writeProgram();
}
}
}
public class NoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 13) {
System.out.println("当前时间:" + w.getHour() + "点 饿了,午饭;犯困,午休");
} else {
// 超过13点,则转入下午工作状态
w.setState(new AfternoonState());
w.writeProgram();
}
}
}
下午和傍晚工作状态类。
public class AfternoonState extends State {
@Override
public void writeProgram(Work w) {
if (w.getHour() < 17) {
System.out.println("当前时间:" + w.getHour() + "点 下午状态不错,继续努力");
} else {
w.setState(new EveningState());
w.writeProgram();
}
}
}
public class EveningState extends State {
@Override
public void writeProgram(Work w) {
if (w.isFinished()) {
// 如果完成任务,则转入下班状态
w.setState(new RestState());
} else {
if (w.getHour() < 21) {
System.out.println("当前时间:" + w.getHour() + "点 加班中...");
} else {
// 超过21点,则转入睡眠工作状态
w.setState(new SleepState());
w.writeProgram();
}
}
}
}
睡眠状态和下班休息状态类。
public class SleepState extends State {
@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 不行了,睡着了");
}
}
public class RestState extends State {
@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 下班回家了");
}
}
工作类,此时没有了过长的分支判断语句。
public class Work {
private State current;
public Work() {
// 工作初始化为上午工作状态,即上午9点开始上班
current = new ForenoonState();
}
// “钟点”属性,状态转换的依据
private double hour;
// “任务完成”属性,是否能下班的依据
private boolean finished = false;
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
public void setState(State current) {
this.current = current;
}
public void writeProgram() {
current.writeProgram(this);
}
}
客户端代码。
public class Client {
public static void main(String[] args) {
Work w = new Work();
w.setHour(9);
w.writeProgram();
w.setHour(10);
w.writeProgram();
w.setHour(12);
w.writeProgram();
w.setHour(13);
w.writeProgram();
w.setHour(14);
w.writeProgram();
w.setHour(17);
w.writeProgram();
// 未完成工作
w.setFinished(false);
w.setHour(19);
w.writeProgram();
w.setHour(22);
w.writeProgram();
}
}
当前时间:9.0点 精神百倍
当前时间:10.0点 精神百倍
当前时间:12.0点 饿了,午饭;犯困,午休
当前时间:13.0点 下午状态不错,继续努力
当前时间:14.0点 下午状态不错,继续努力
当前时间:17.0点 加班中...
当前时间:19.0点 加班中...
当前时间:22.0点 不行了,睡着了
Process finished with exit code 0
参考书籍:
《大话设计模式》