状态模式容许一个对象在其内部状态改变时改变它的行为。用电梯来举例,电梯能够认为具备开门、关门、运行、中止四种状态,这四种状态之间的切换具备多种限制,好比在开门状态下不电梯不能运行,只能转为关门状态;在运行状态下,电梯只能转为中止状态...
设想一下,若是要常规的if-else或者switch-case描述电梯的这几种状态间的切换,将生成很是复杂的、逻辑相互交织的代码,可读性差且不易维护。设计模式
而若是用状态模式来实现,会是怎样的呢?
首先建立LiftState,表明抽象的电梯状态,包含了电梯的四个动做(方法),经过这些方法能够切换到对应的状态。app
public abstract class LiftState { protected Context context; public void SetContext(Context context) { this.context = context; } public abstract void Open(); public abstract void Close(); public abstract void Run(); public abstract void Stop(); }
Context是上下文类,它的做用是串联各个状态的过渡,在LiftSate抽象类中把Context类角色聚合进来,并传递到子类,这样4个具体的实现类中本身根据环境来决定如何进行状态的过渡。ide
public class Context { public readonly static OpenningState openningState = new OpenningState(); public readonly static ClosingState closingState = new ClosingState(); public readonly static RunningState runningState = new RunningState(); public readonly static StoppingState stoppingState = new StoppingState(); private LiftState liftState; public LiftState LiftState { get { return liftState; } set { liftState = value; liftState.SetContext(this); } } public void Open() { this.liftState.Open(); } public void Close() { this.liftState.Close(); } public void Run() { this.liftState.Run(); } public void Stop() { this.liftState.Stop(); } }
接下来是四个具体的状态类,负责状态之间的切换和控制,以OpenningState为例,只能切换到Closing状态,其它切换状态的方法都是空实现。this
public class OpenningState : LiftState { public override void Close() { base.context.LiftState = Context.closingState; base.context.LiftState.Close(); } public override void Open() { Console.WriteLine("Openning"); } public override void Run() { // } public override void Stop() { // } } public class ClosingState : LiftState { public override void Close() { Console.WriteLine("Closing"); } public override void Open() { base.context.LiftState = Context.openningState; base.context.LiftState.Open(); } public override void Run() { base.context.LiftState = Context.runningState; base.context.LiftState.Run(); } public override void Stop() { base.context.LiftState = Context.stoppingState; base.context.LiftState.Stop(); } } public class RunningState : LiftState { public override void Close() { // } public override void Open() { // } public override void Run() { Console.WriteLine("Running"); } public override void Stop() { base.context.LiftState = Context.stoppingState; base.context.LiftState.Stop(); } } public class StoppingState : LiftState { public override void Close() { // } public override void Open() { base.context.LiftState = Context.openningState; base.context.LiftState.Open(); } public override void Run() { base.context.LiftState = Context.runningState; base.context.LiftState.Run(); } public override void Stop() { Console.WriteLine("Stopping"); } }
经过上面的例子能够直观得看到状态模式的特色,它的核心是封装,状态的变动引发了行为的变动,从外部看起来就好像这个对象对应的类发生了改变同样。
GOF对状态模式的描述为:
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
— Design Patterns : Elements of Reusable Object-Oriented Software设计
状态模式的UML类图为
code
状态模式中有3个角色:对象
public abstract class State { protected Context context; public void SetState(Context context) { this.context = context; } public abstract void Handle1(); public abstract void Handle2(); } public class ConcreteState1 : State { public override void Handle1() { //本状态下必须处理的逻辑 } public override void Handle2() { base.context.CurrentState = Context.STATE2; base.context.Handle2(); } } public class ConcreteState2 : State { public override void Handle1() { base.context.CurrentState = Context.STATE1; base.context.Handle1(); } public override void Handle2() { //本状态下必须处理的逻辑 } } public class Context { public readonly static State STATE1 = new ConcreteState1(); public readonly static State STATE2 = new ConcreteState2(); private State currentState; public State CurrentState { get { return currentState; } set { this.currentState = value; this.currentState.SetState(this); } } public void Handle1() { this.CurrentState.Handle1(); } public void Handle2() { this.CurrentState.Handle2(); } }
关于Context类,一般的作法是把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。并且环境角色具备状态抽象角色定义的全部行为,具体执行使用委托方式。blog
调用端代码:接口
public class Test { public static void Entry() { Context context = new Context(); context.CurrentState = Context.STATE1; context.Handle1(); context.Handle2(); } }
优势get
缺点
状态模式主要的缺点在于,随着状态的增长,子类会变得太多。
参考书籍: 王翔著 《设计模式——基于C#的工程化实现及扩展》