工作上班,我们每个人在不同时间段都有不同的工作状态。上午精神状态最好,中午吃完饭就犯困,下午精神状态就下降了,如果工作没做完,晚上加班到很晚,那就崩溃了。那我们就用代码来实现一下这种工作状态的变化。
第一版:
public class Work { private int hour; private boolean finished; public int getHour() { return hour; } public void setHour(int hour) { this.hour = hour; } public boolean isFinished() { return finished; } public void setFinished(boolean finished) { this.finished = finished; } public void writeProgram(){ if(hour < 12){ System.out.println("当前时间:" + hour + "点 上午工作,精神百倍"); }else if(hour < 14){ System.out.println("当前时间:" + hour + "点 饿了,午饭,困了,午休"); }else if(hour < 17){ System.out.println("当前时间:" + hour + "点 下午状态不错, 继续努力"); }else{ if(finished){ System.out.println("当前时间:" + hour + "点 下班回家了"); }else{ if(hour < 22){ System.out.println("当前时间:" + hour + "点 加班,疲累至极"); }else{ System.out.println("当前时间:" + hour + "点 不行了,睡着了"); } } } } }
public class Test { public static void main(String[] args) { Work emergencyWork = new Work(); emergencyWork.setHour(9); emergencyWork.writeProgram(); emergencyWork.setHour(10); emergencyWork.writeProgram(); emergencyWork.setHour(13); emergencyWork.writeProgram(); emergencyWork.setHour(16); emergencyWork.writeProgram(); emergencyWork.setFinished(false); emergencyWork.setHour(19); emergencyWork.writeProgram(); emergencyWork.setHour(22); emergencyWork.writeProgram(); } }
方法过长,就有了坏味道。方法中判断分支过多,则说明其责任过大,无论什么工作状态,都需要它来改变,这很糟糕。面向对象设计其实就是希望做到代码的责任分解。Work这个类违背了“单一职责原则”。
状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
状态模式的好处是把与特定状态相关的行为局部化,并且将不同状态的行为分割开来。这样做的目的是消除庞大的条件分支语句,大的分支判断会难以修改和扩展,而状态模式可以减少相互间的依赖,此时就容易扩展和维护了。
第二版,状态模式版
public abstract class State1 { public abstract void writeProgram(Work1 w); }
public class ForenoonState extends State1{ public void writeProgram(Work1 w) { if(w.getHour() < 12){ System.out.println("当前时间:" + w.getHour() + "点 上午工作,精神百倍"); }else{ w.setCurrent(new NoonState()); w.writeProgram(); } } }
public class NoonState extends State1{ public void writeProgram(Work1 w) { if(w.getHour() < 13){ System.out.println("当前时间:" + w.getHour() + "点 饿了,午饭;犯困,午休"); }else{ w.setCurrent(new AfternoonState()); w.writeProgram(); } } }
public class AfternoonState extends State1{ public void writeProgram(Work1 w) { if(w.getHour() < 17){ System.out.println("当前时间:" + w.getHour() + "点 下午状态不错,继续努力"); }else{ w.setCurrent(new EveningState()); w.writeProgram(); } } }
public class EveningState extends State1{ public void writeProgram(Work1 w) { if(w.isFinished()){ 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 State1{ public void writeProgram(Work1 w) { System.out.println("当前时间:" + w.getHour() + "点 下班回家了"); } }
public class SleepingState extends State1{ public void writeProgram(Work1 w) { System.out.println("当前时间:" + w.getHour() + "点 不行了,睡着了"); } }
public class Work1 { private int hour; private boolean finished; private State1 current; public Work1(){ current = new ForenoonState(); } public int getHour() { return hour; } public void setHour(int hour) { this.hour = hour; } public boolean isFinished() { return finished; } public void setFinished(boolean finished) { this.finished = finished; } public void writeProgram(){ current.writeProgram(this); } public State1 getCurrent() { return current; } public void setCurrent(State1 current) { this.current = current; } }
public class Test2 { public static void main(String[] args) { Work1 emergencyWork = new Work1(); emergencyWork.setHour(9); emergencyWork.writeProgram(); emergencyWork.setHour(10); emergencyWork.writeProgram(); emergencyWork.setHour(13); emergencyWork.writeProgram(); emergencyWork.setHour(16); emergencyWork.writeProgram(); emergencyWork.setFinished(false); emergencyWork.setHour(19); emergencyWork.writeProgram(); emergencyWork.setHour(22); emergencyWork.writeProgram(); } }
客户端代码没大的改动,但我们的程序更加灵活易变了。如果我们增加一个“强制下班状态”,我们只要改动一下“傍晚工作状态”类的判断条件就可以了,而不影响其他状态类的代码。