不用状态模式的案例
public class WriteProgram {
int hour = 0;
boolean workFinished = false;
public void writeProgram() {
if (hour < 12) {
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 + " 不行了,睡着了");
}
}
}
}
这个方法很长,而且有很多判断分支,也就意味着它的责任过大了,无论是任何状态,都需要通过它来改变,这实际上是很糟糕的。任何需求的改动或增加,都需要去更改这个方法,维护出错的风险很大。
面向对象设计其实就是希望做到代码的责任分解。这个类违背了“开放-封闭原则”。
改成状态模式后
public class Work {
private int hour ;
private boolean workFinished;
private State state;
public Work() {
this.state = new ForenoonState();
}
public void writeProgram(){
state.writeProgram(this);
}
public abstract class State {
abstract void writeProgram(Work work);
}
public class ForenoonState extends State {
@Override
void writeProgram(Work work) {
if(work.getHour()<12){
System.out.println("当前时间:" + work.getHour() + " 上午工作,精神百倍");
}else{
work.setState(new NoonState());
work.writeProgram();
}
}
}
public class AfternoonState extends State {
@Override
void writeProgram(Work work) {
if (work.getHour() < 17) {
System.out.println("当前时间:" + work.getHour() + " 下午状态不错,继续努力");
} else{
work.setState(new EveningState());
work.writeProgram();
}
}
}
public class EveningState extends State {
@Override
void writeProgram(Work work) {
if (work.isWorkFinished()) {
work.setState(new RestState());
work.writeProgram();
} else {
if (work.getHour() < 21) {
System.out.println("当前时间:" + work.getHour() + " 加班哦,疲累之极");
} else {
work.setState(new SleepingState());
work.writeProgram();
}
}
}
}
public class RestState extends State {
@Override
void writeProgram(Work work) {
System.out.println("当前时间:" + work.getHour() + " 下班回家");
}
}
public class SleepingState extends State {
@Override
void writeProgram(Work work) {
System.out.println("当前时间:" + work.getHour() + " 不行了,睡着了");
}
}
public class Main {
public static void main(String[] args) {
Work work=new Work();
work.setHour(9);
work.writeProgram();
work.setHour(13);
work.writeProgram();
}
}
Work代表环境的变化,Work中的State代表要执行的子类,如果子类不是想要的,就传递给下一个子类,一直到找到对应的子类执行。如果不需要子类传递,子类中可以不设置Work中的State。
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。如果这个状态判断很简单,就没必要用状态模式了。
状态模式的好处:将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易的增加新的状态和转换。这样做的目的就是为了消除庞大的条件分支语句,大的分支判断会使得他们难以修改和扩展,状态模式通过把各种状态转移逻辑分部到State的子类之间,来减少相互间的依赖。
什么时候使用状态模式?
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改版它的行为时,就可以考虑使用状态模式了。