状态模式,个人认为通过将对象行为包装在不同状态对象里面,通过控制状态的变化来实现行为的差异。关于状态模式的使用场景,如果一个对象在不同状态(至少3个状态)下有不同行为,而且还有增加状态的趋势,可以考虑使用状态模式。拿电梯(来源于Java 设计模式——状态模式)来说,众所周知,电梯至少有四种状态: 开门状态,关门状态,运行状态,停止状态。
下面用一张表将状态和对应的动作列出来:
对应的状态图:
为了有所区别,每个状态之间的联系是不一样的,如Closed状态和其他状态之间用虚线,而open状态和closed状态之前使用实线,可以看出,状态图和上面的表格是一致的。 下面再看看代码实现:
public interface IElevator { void open(); void close(); void run(); void stop(); }
1 public class Elevator implements IElevator { 2 3 @Override 4 public void open() { 5 System.out.println("open the elevator"); 6 } 7 8 @Override 9 public void close() { 10 System.out.println("close the elevator"); 11 } 12 13 @Override 14 public void run() { 15 System.out.println("run the elevator"); 16 } 17 18 @Override 19 public void stop() { 20 System.out.println("stop the elevator"); 21 } 22 }
public class Context { /*package*/ final State openState = new OpenState(this); /*package*/ final State closedState = new ClosedState(this); /*package*/ final State runningState = new RunningState(this); /*package*/ final State stoppedState = new StoppedState(this); /*package*/ final IElevator elevator; private State state; public Context(IElevator elevator) { this.elevator = elevator; this.state = openState; } public IElevator getElevator() { return elevator; } public void setState(State state) { this.state = state; } public void open() { state.open(); } public void close() { state.close(); } public void run() { state.run(); } public void stop() { state.stop(); } public static void main(String[] param) { Context context = new Context(new Elevator()); context.close(); context.run(); context.open(); } }
public abstract class State implements IElevator { protected final Context context; public State(Context context) { this.context = context; } protected void log(String state, String action) { System.out.println("Elevator can't take action " + action + " in state " + state); } }
public class OpenState extends State { public OpenState(Context context) { super(context); } @Override public void open() { log("open", "open"); } @Override public void close() { context.getElevator().close(); context.setState(context.closedState); } @Override public void run() { log("open", "run"); } @Override public void stop() { log("open", "stop"); } }
public class ClosedState extends State { public ClosedState(Context context) { super(context); } @Override public void open() { context.getElevator().open(); context.setState(context.openState); } @Override public void close() { log("closed", "close"); } @Override public void run() { context.getElevator().run(); context.setState(context.runningState); } @Override public void stop() { context.getElevator().stop(); context.setState(context.stoppedState); } }
public class RunningState extends State { public RunningState(Context context) { super(context); } @Override public void open() { log("running", "open"); } @Override public void close() { log("running", "close"); } @Override public void run() { log("running", "run"); } @Override public void stop() { context.getElevator().stop(); } }
public class StoppedState extends State { public StoppedState(Context context) { super(context); } @Override public void open() { context.getElevator().open(); context.setState(context.openState); } @Override public void close() { log("stopped", "close"); } @Override public void run() { context.getElevator().run(); context.setState(context.runningState); } @Override public void stop() { log("stopped", "stop"); } }
代码和简单,类图如下:
现在问题来了,新闻上经常报告电梯出事,上级要求每个电梯添加急救按钮,用户在紧急情况下可以按下此按钮逃生。想想看,如果之前没有使用状态模式,拿到这个需求程序员是不是有想死的冲动 , 而状态模式能很好解决这个需求只需要添加urgent动作就可以了。
如果各位还不过瘾,我想再拿个打电话的小例子,状态图如下:
如果手机新增一个urgent功能:
具体代码我就不展示了,具体代码可以参见: https://github.com/breakJeff/designPattern,如果发现问题,请及时留言。