状态模式
今天要说的设计模式——状态模式,个人觉得非常有意思,因为此种设计模式的运用场景几乎可以说是每个程序里都可以用上。当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。定义一般来说都是晦涩难懂的。我们同样来通俗一点解释,首先解释这种模式的运用场景,这种模式一般用在有大量if-else的分支判断上,不同的状态也就表示为不同的if条件,进入不同的if分支执行操作后就好像是改变了其类。
这就是状态模式的UML类结构图,其实在这里看UML类结构图还是有点蒙逼的样子,if-else分支这种场景经常遇到,比如在eclipse里会有一个checkstyle插件,在这个插件可以检查是否分支过多,以前觉得这个分支本来就这么多啊,需要做这么多判断啊,我怎么去拆分。但看了这个状态模式过后才知道其实不然,有大量的if-else分支判断,说明在这个类里它的责任过大,无论任何状态,都需要通过它来改变,而面向对象设计其实就是希望做到代码的责任分解。
我们如果有这么一段if-else代码需要做分解,那该怎么办?
if (hour< 12) { System.out.println("状态1:" + hour); } else if (hour < 18) { System.out.println("状态2:" + hour); } else { System.out.println("状态2:" + hour); }
上面的场景中,我们在实际当中可能还会遇到更多的分支。说了那么多,我们直接实现代码来看,状态模式是如何做到将if-else分支分解的。
1 package day_25_state; 2 3 /** 4 * 状态接口 5 * @author turbo 6 * 7 * 2016年9月25日 8 */ 9 public interface State { 10 void handle(Context context); 11 }
1 package day_25_state; 2 3 /** 4 * 状态1 5 * @author turbo 6 * 7 * 2016年9月25日 8 */ 9 public class ConcreteState1 implements State { 10 11 /* (non-Javadoc) 12 * @see day_25_state.State#handle(day_25_state.Context) 13 */ 14 @Override 15 public void handle(Context context) { 16 if (context.getHour() < 13){ 17 System.out.println("状态1:时间" + context.getHour()); 18 } else { 19 context.setState(new ConcreteState2()); 20 context.handle(); 21 } 22 } 23 24 }
1 package day_25_state; 2 3 /** 4 * 状态2 5 * 6 * @author turbo 7 * 8 * 2016年9月25日 9 */ 10 public class ConcreteState2 implements State { 11 12 /* 13 * (non-Javadoc) 14 * 15 * @see day_25_state.State#handle(day_25_state.Context) 16 */ 17 @Override 18 public void handle(Context context) { 19 if (context.getHour() < 18) { 20 System.out.println("状态2:时间" + context.getHour()); 21 } else { 22 context.setState(new ConcreteState3()); 23 context.handle(); 24 } 25 } 26 27 }
1 package day_25_state; 2 3 /** 4 * 状态3 5 * @author turbo 6 * 7 * 2016年9月25日 8 */ 9 public class ConcreteState3 implements State { 10 11 /* (non-Javadoc) 12 * @see day_25_state.State#handle(day_25_state.Context) 13 */ 14 @Override 15 public void handle(Context context) { 16 System.out.println("状态3:" + context.getHour()); 17 } 18 19 }
注意看上面3个具体状态的else分支语句。
下面是是Context类,可以理解为它就是“寻找、判断”当前状态是什么。
1 package day_25_state; 2 3 /** 4 * 用来定义当前状态 5 * @author turbo 6 * 7 * 2016年9月25日 8 */ 9 public class Context { 10 private State state; 11 private double hour; 12 13 public double getHour() { 14 return hour; 15 } 16 17 public void setHour(double hour) { 18 this.hour = hour; 19 } 20 21 public void setState(State state) { 22 this.state = state; 23 } 24 25 public Context(){ 26 state = new ConcreteState1(); //初始化为状态1,可以理解为我们的第一个if判断 27 } 28 29 public void handle(){ 30 state.handle(this); 31 } 32 }
客户端代码:
1 package day_25_state; 2 3 /** 4 * 客户端测试代码 5 * @author turbo 6 * 7 * 2016年9月25日 8 */ 9 public class Main { 10 11 /** 12 * @param args 13 */ 14 public static void main(String[] args) { 15 Context context = new Context(); 16 context.setHour(15); 17 context.handle(); 18 } 19 20 }
强烈建议,自己手动敲一遍状态模式的代码,不管看不看得懂代码,但是手敲一遍一定会懂!个人觉得这个模式非常重要和实用,以前从未想过此种用法,从来都是面向过程的思想在写代码,要学的太多,要彻底将面向过程的思维转换为面向对象。前面一开始就说过,面向对象编程,不是用一门面向对象的语言编程。
不积跬步,无以至千里;不积小流,无以成江海。