状态模式
状态模式(State):当一个对象的内在状态变化时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化。
当然了,如果这个状态判断很简单,那么就没必要使用状态模式了。
状态模式(State)结构图
- State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
public abstract class State {abstract void handle(Context context);
}
- ConcreteState类,具体状态,每一个子类实现一个与Context的一个状态相关的行为。
// 具体状态A类
public class ConcreteStateA extends State {@Overridevoid handle(Context context) {// 设置下一个状态是B类对象context.setState(new ConcreteStateB());}
}
// 具体状态B类
public class ConcreteStateB extends State {@Overridevoid handle(Context context) {// 设置下一个状态是A类对象context.setState(new ConcreteStateA());}
}
- Context,维护一个State对象,这个实例对象定义当前的状态
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 {@Overridevoid writeProgram(Work w) {if (w.getHour() < 12) {System.out.println("当前时间:" + w.getHour() + "点 上午工作 精神百倍!");} else {w.setCurrent(new NoonState());w.writeProgram();}}
}// 中午工作状态
public class NoonState extends State {@Overridevoid writeProgram(Work w) {if (w.getHour() < 13) {System.out.println("当前时间:" + w.getHour() + "点 饿了,去干饭,犯困,午休");} else {w.setCurrent(new AfternoonState());w.writeProgram();}}
}// 下午工作状态
public class AfternoonState extends State {@Overridevoid writeProgram(Work w) {if (w.getHour() < 17) {System.out.println("当前时间:" + w.getHour() + "点 下午状态还行,继续努力");} else {w.setCurrent(new EveningState());w.writeProgram();}}
}// 晚间工作状态
public class EveningState extends State {@Overridevoid 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 {@Overridevoid writeProgram(Work w) {System.out.println("当前时间:" + w.getHour() + "点 嘎嘎累 要睡着了");}
}// 下班
public class RestState extends State {@Overridevoid 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类中,所以通过定义新的子类可以很容易增加新的状态和转换。
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就需要考虑使用状态模式了了。