允许一个对象在其内部状态改变时改变它的行为,让对象看起来似乎修改了它的类
介绍
状态模式中主要有2个类,分别是Work和State,今天我们利用工作的状态来理解状态模式,比如,我们在工作的时候,根据时间的不同,有以下几种状态。
- 12点之前:精神百倍
- 12 - 13点:饿了,午饭:犯困,午休
- 13 - 17点:下午状态还不错,继续努力
- 17 - 21点:可能加班,也可能被强制回家
- 21点之后:不行了,睡着了。
上面的场景,我们可以看出,我们的工作状态和时间有关(或者被强制回家)。
所以,我们希望设计一个State类,这个State类代表工作中的时间状态,同时,它可以根据不同的时间状态修改Work的其他状态。
这种当一个对象的内在状态改变时允许改变类的行为,我们称为状态模式。也就是说,Work的行为和State有关。
UML图
状态模式的UML图可能有些复杂,可以结合代码理解
Work类
work类中有3个属性:
- current:代表当前的状态,这个状态会随hour改变而改变
- hour:时间,也就是引起变化的原因
- finish:这个不用太关注,也就另外一个引起变化的原因的例子
writeProgram()方法:
- 它的作用是,当current发生变化时,通知State接口的子类,让符合要求的State的子类来改变Work的行为
State接口:
下面有6个实现类,实现的方式都差不多,也就不一一介绍了,它的作用是,根据Work的时间状态,从ForenoonState开始判断(途中的虚线箭头),如果找到满足当前时间的状态,就用当前的类,去修改Work的状态;比如途中的NoonState类。
这种回调的修改状态的方式,简化了Work类的逻辑,可以让他专注与自生的业务逻辑,State的子类虽然多了,但是它减少了一系列的if else 的判断语句,也就让逻辑判断更加清晰了
代码
如果上面的原理明白了,代码也就很简单了,如果还不懂,敲一遍代码也对理解状态模式是一个很好的帮助。
- Work类
public class Work {
private State current;//当前状态
private double hour;//时间
private boolean finish = false;//结束
public Work(){
current = new ForenoonState();
}
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
public boolean getFinish() {
return finish;
}
public void setFinish(boolean finish) {
this.finish = finish;
}
public State getCurrent() {
return current;
}
public void setCurrent(State current) {
this.current = current;
}
public void writeProgram(){
current.writeProgram(this);
}
}
- State接口
public abstract class State {
public abstract void writeProgram(Work w);
}
- 下面是State的子类,逻辑都差不多
public class ForenoonState extends State{
@Override
public 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
public 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
public 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
public void writeProgram(Work w) {
if(w.getFinish()){
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 RestState extends State {
@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点下班回家了。");
}
}
public class SleepingState extends State {
@Override
public void writeProgram(Work w) {
System.out.println("当前时间:" + w.getHour() + "点 不行了,睡着了。");
}
}
- 使用方式,和打印结果
public class Demo {
public static void main(String[] args) {
Work emergencyProjects = new Work();
emergencyProjects.setHour(9);
emergencyProjects.writeProgram();
emergencyProjects.setHour(10);
emergencyProjects.writeProgram();
emergencyProjects.setHour(12);
emergencyProjects.writeProgram();
emergencyProjects.setHour(13);
emergencyProjects.writeProgram();
emergencyProjects.setHour(14);
emergencyProjects.writeProgram();
emergencyProjects.setHour(17);
emergencyProjects.setFinish(false);
emergencyProjects.writeProgram();
emergencyProjects.setHour(19);
emergencyProjects.writeProgram();
emergencyProjects.setHour(22);
emergencyProjects.writeProgram();
}
}
当前时间:9.0点 上午工作,精神百倍
当前时间:10.0点 上午工作,精神百倍
当前时间:12.0点 饿了,午饭:犯困,午休。
当前时间:13.0点 下午状态还不错,继续努力。
当前时间:14.0点 下午状态还不错,继续努力。
当前时间:17.0点 加班哦,疲惫之极
当前时间:19.0点 加班哦,疲惫之极
当前时间:22.0点 不行了,睡着了。
总结
- 状态模式主要是将逻辑判断非常多的情况下,将每个逻辑判断分拆成不同的类,这样有助于后期的代码维护和他人对代码的逻辑的理解。
- 如果后期业务逻辑有修改,修改或增加单个判断,也不会影响其他的逻辑判断
- 但如果业务的逻辑判断并不多,也就不必要用状态模式了