设计模式-状态模式(State Pattern)
本文由@呆代待殆原创,转载请注明出处:http://www.cnblogs.com/coffeeSS/
状态模式简介
状态模式允许一个对象在其内部状态改变的时候改变它的行为,他的内部会存着好几种状态,在当前状态发生变化是,这个对象执行和之前相同的操作也会有不同的作用效果。
状态模式的定义和基本结构
定义:状态模式允许一个对象在其内部状态改变的时候改变它的行为,就像变成了另一个对象一样。
一张来自《Head First》的结构图
Context:这个类里面包含了很多种状态类,当前状态不同时,这个类的行为会发生变化。
State:所有状态类的超类,也是Context里使用状态类的接口,里面包含了所以会引起状态变化的方法。
ConcreteState:某种状态的实现。
一个简单的例子(java)
假设我们有一个多功能灯,只有一个按钮,灯有如下状态:关闭、白光、暖光、舞台灯光。按下按钮,灯就在这4个状态中依次切换。我们用状态模式来模拟这个过程。我们需要一个MyLamp类,一个State超类,和四个状态类。
首先给出State超类,和4个状态类。因为我们只有一个改变状态的操作,所以只有一个方法就够了,另外状态类和MyLamp类耦合比较强,所以先写那个都无所谓(反正中途会碰到未声明的错误)。
1 public abstract class State { 2 private MyLamp lamp; 3 public State(MyLamp lamp){ 4 this.lamp=lamp; 5 } 6 public MyLamp getLamp() { 7 return lamp; 8 } 9 public abstract void pushButton(); 10 } 11 12 public class LampClose extends State { 13 public LampClose(MyLamp lamp) { 14 super(lamp); 15 } 16 @Override 17 public void pushButton() { 18 getLamp().setCurrentState(getLamp().getLw()); 19 System.out.println("当前状态:"+getLamp().getCurrentState().getClass().getName()); 20 } 21 } 22 23 public class LampWhite extends State { 24 public LampWhite(MyLamp lamp) { 25 super(lamp); 26 } 27 @Override 28 public void pushButton() { 29 getLamp().setCurrentState(getLamp().getLf()); 30 System.out.println("当前状态:"+getLamp().getCurrentState().getClass().getName()); 31 } 32 } 33 34 public class LampFluorescent extends State { 35 public LampFluorescent(MyLamp lamp) { 36 super(lamp); 37 } 38 @Override 39 public void pushButton() { 40 getLamp().setCurrentState(getLamp().getLcf()); 41 System.out.println("当前状态:"+getLamp().getCurrentState().getClass().getName()); 42 } 43 } 44 45 public class LampColourful extends State { 46 public LampColourful(MyLamp lamp) { 47 super(lamp); 48 } 49 @Override 50 public void pushButton() { 51 getLamp().setCurrentState(getLamp().getLc()); 52 System.out.println("当前状态:"+getLamp().getCurrentState().getClass().getName()); 53 } 54 }
然后给出MyLamp类的实现。
1 public class MyLamp { 2 private LampClose lc; 3 private LampWhite lw; 4 private LampFluorescent lf; 5 private LampColourful lcf; 6 private State currentState; 7 public MyLamp(){ 8 lc=new LampClose(this); 9 lw=new LampWhite(this); 10 lf=new LampFluorescent(this); 11 lcf=new LampColourful(this); 12 currentState=lc; 13 System.out.println("当前状态:"+getCurrentState().getClass().getName()); 14 } 15 public void push(){ 16 currentState.pushButton(); 17 } 18 public State getCurrentState() { 19 return currentState; 20 } 21 public void setCurrentState(State currentState) { 22 this.currentState = currentState; 23 } 24 public LampClose getLc() { 25 return lc; 26 } 27 public LampWhite getLw() { 28 return lw; 29 } 30 public LampFluorescent getLf() { 31 return lf; 32 } 33 public LampColourful getLcf() { 34 return lcf; 35 } 36 }
最后给出测试类。
1 public class Test { 2 public static void main(String[] args) { 3 MyLamp ml=new MyLamp(); 4 ml.push(); 5 ml.push(); 6 ml.push(); 7 ml.push(); 8 ml.push(); 9 ml.push(); 10 ml.push(); 11 ml.push(); 12 ml.push(); 13 ml.push(); 14 ml.push(); 15 } 16 }
测试中,我们不停的调用push()方法,我们会发现输出是不一样的,因为MyLamp的状态一直在不停转换。
输出如下:
状态模式和策略模式
敏感的朋友可能发现状态模式和策略模式的类图看起来一模一样,确实,他们有着相似的地方,但是他们的内涵差距还是挺大的,策略模式中,策略的决定权在用户手中,用户决定给类set哪一个需要的策略类,而状态模式中,context类里面已经包含了所有的状态类,转换规则也已经内化到了代码中,用户只需要执行操作,状态的转换对应用户来说是透明的,他们能感觉到的只有类的行为的变化而已。
状态模式到此结束,♪(^∇^*)
参考资料:《Head First 设计模式》