今天来介绍一个新的设计模式----状态模式。
如果我要你写一个关于工作的程序你会怎么写呢?具体要求如下:
9-12点,早上,状态是精力充沛。 12-13点,中午,吃饭。 13-17点,傍晚,状态一般。 一般来说17点下班,但是有可能当天工作繁重要求加班。 加班的话:17-21点,晚上,疲累至极。 21点往后状态:顶不住了,累晕了。
如果这些要求都写在一个方法里的话,那么代码就太多了,而且如果有什么改动会十分麻烦,还破坏了封闭-开放原则。
今天介绍的这个模式就可以解决代码繁杂的问题。
首先来介绍一下这个状态模式:
状态模式: 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类中。
状态类:
/** * @author 陈柏宇 */ public abstract class State { abstract void handle(Context context); } class ConcreteStateA extends State{ /* 设置ConcreteStateA的下一状态是ConcreteStateB */ @Override void handle(Context context) { context.setState(new ConcreteStateB()); } } class ConcreteStateB extends State{ /* 设置ConcreteStateB的下一状态是ConcreteStateA */ @Override void handle(Context context) { context.setState(new ConcreteStateA()); } }
Context类:
/** * @author 陈柏宇 * 定义当前状态的实例 */ public class Context { private State state; public Context(State state) { /* 定义Context的初始状态 */ this.state = state; System.out.println("初始状态为:" + state.getClass().getName()); } /* 可读写的状态属性,用于读取当前状态和设置新状态。 */ public void setState(State state) { this.state = state; System.out.println("当前状态:" + state.getClass().getName()); } public State getState() { return this.state; } /* 对请求做处理,并设置下一状态。 */ public void request() { state.handle(this); } }
客户端代码:
public static void main(String[] args) { Context c = new Context(new ConcreteStateA()); c.request(); c.request(); c.request(); c.request(); }
输出:
初始状态为:template.ConcreteStateA 当前状态:template.ConcreteStateB 当前状态:template.ConcreteStateA 当前状态:template.ConcreteStateB 当前状态:template.ConcreteStateA
那么我刚刚举的那个例子又该怎么用状态模式写呢:
状态类:
分为:上午工作状态、中午工作状态、下午工作状态、傍晚工作状态、下班状态、睡眠工作状态。
/** * @author 陈柏宇 * 状态类 */ public abstract class State { abstract void wirteProgram(Work w); } /* 上午工作状态 */ class ForenoonState extends State{ @Override void wirteProgram(Work w) { if(w.getHour() < 12) { System.out.println("当前时间:" + w.getHour() + ",精力充沛!"); } else { w.setCurrent(new NoonState()); w.wirteProgram(); } } } /* 中午工作状态 */ class NoonState extends State{ @Override void wirteProgram(Work w) { if(w.getHour() < 13) { System.out.println("当前时间:" + w.getHour() + ",饿了,去吃饭"); } else { w.setCurrent(new AfternoonState()); w.wirteProgram(); } } } /* 下午工作状态 */ class AfternoonState extends State{ @Override void wirteProgram(Work w) { if(w.getHour() < 17) { System.out.println("当前时间:" + w.getHour() + ",下午状态不错,继续努力!"); } else { w.setCurrent(new EveningState()); w.wirteProgram(); } } } /* 傍晚工作状态 */ class EveningState extends State{ @Override void wirteProgram(Work w) { if (w.isFinish()) { w.setCurrent(new RestState()); w.wirteProgram(); } else { if(w.getHour()<21) { System.out.println("当前时间:" + w.getHour() + ",加班哇,好困好困!"); } else { w.setCurrent(new SleepingState()); w.wirteProgram(); } } } } /* 睡眠工作状态 */ class SleepingState extends State { @Override void wirteProgram(Work w) { System.out.println("当前时间:" + w.getHour() + ",不行了,睡着了。"); } } /* 下班休息状态 */ class RestState extends State { @Override void wirteProgram(Work w) { System.out.println("当前时间:" + w.getHour() + ",下班回家了。"); } }
工作类:
/** * @author 陈柏宇 * 工作类 */ public class Work { private State current; private double hour; private boolean finish = false; public double getHour() { return hour; } public void setHour(double hour) { this.hour = hour; } public boolean isFinish() { return finish; } public void setFinish(boolean finish) { this.finish = finish; } public Work() { current = new ForenoonState(); //初始状态 } public void setCurrent(State state) { current = state; } public void wirteProgram() { current.wirteProgram(this); } }
客户端:
public static void main(String[] args) { Work work = new Work(); work.setHour(9); work.wirteProgram(); work.setHour(10); work.wirteProgram(); work.setHour(12); work.wirteProgram(); work.setHour(13); work.wirteProgram(); work.setHour(14); work.wirteProgram(); work.setHour(17); //work.setFinish(true); work.setFinish(false); work.wirteProgram(); work.setHour(19); work.wirteProgram(); work.setHour(22); work.wirteProgram(); }
控制台输出:
当前时间:9.0,精力充沛! 当前时间:10.0,精力充沛! 当前时间:12.0,饿了,去吃饭 当前时间:13.0,下午状态不错,继续努力! 当前时间:14.0,下午状态不错,继续努力! 当前时间:17.0,加班哇,好困好困! 当前时间:19.0,加班哇,好困好困! 当前时间:22.0,不行了,睡着了。
这样写的好处是如果我们想要改变需求的细节,比如老板规定20:00以后必须下班回家,那么我们就可以在工作类里面添加一种状态(老板是否规定20:00以后回家)
然后在晚上状态中新添加判断条件就可以了。
当一个对象的行为取决于它的状态,并且它必须在运行的时刻根据状态改变它的行为时,就可以考虑使用状态模式了。