状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转到到表示不同状态的一系列类当中,可以把复杂的逻辑判断简化。当然,如果这个状态的判断很简单,就没有必要使用状态模式了。
如果我没理解错的话,说白了就是如果判断很长,就把判断分割到多个类里面。
状态模式的好处是将与特定状态相关的行为局部化,并且将不同状态的行为分隔开来。状态模式通过吧各种状态转移逻辑分布到State子类之间,来减少相互间的依赖。
问:什么时候考虑使用状态模式呢?
答:当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。
为什么要叫状态模式呢?因为状态是会变动的,改变状态又改变了行为。
来看下状态模式的UML图:
状态模式的代码结构:
namespace ConsoleApplication1 { abstract class State { public abstract void Handle(Context context); } class Context { private State state; public Context(State state) //定义了Context的初始状态 { this.state = state; } public State State { get { return state; } set { state = value; Console.WriteLine("当前状态:" + state.GetType().Name); } } public void Request() { state.Handle(this); } } class ConcreteStateA : State { public override void Handle(Context context) { context.State = new ConcreteStateB(); //设置ConcreteStateA的下一状态是B } } class ConcreteStateB : State { public override void Handle(Context context) { context.State = new ConcreteStateA(); //设置ConcreteStateB的下一状态是A } } class Program { static void Main(string[] args) { Context c = new Context(new ConcreteStateA()); //设置Context的初始状态为A c.Request(); //不断地请求,同时改变状态 c.Request(); c.Request(); c.Request(); Console.ReadKey(); } } }
输出结果如下:
回到《大话设计模式》中的上班的例子:
namespace ConsoleApplication1 { public abstract class State { public abstract void WriteProgram(Work w); } //上午工作状态 public class ForenoonState : State { public override void WriteProgram(Work w) { if (w.Hour < 12) { Console.WriteLine("当前时间:{0}点 上午工作,精神百倍", w.Hour); } else { w.SetState(new NoonState()); //超过12点,更改工作状态 w.WriteProgram(); } } } //中午工作状态 public class NoonState : State { public override void WriteProgram(Work w) { if (w.Hour < 13) { Console.WriteLine("当前时间:{0}点 饿了,午饭;犯困,午休", w.Hour); } else { w.SetState(new AfterNoonState()); w.WriteProgram(); } } } //下午工作状态 public class AfterNoonState : State { public override void WriteProgram(Work w) { if (w.Hour < 17) { Console.WriteLine("当前时间:{0}点 下午状态真不错,继续努力", w.Hour); } else { w.SetState(new EveningState()); w.WriteProgram(); } } } //晚间工作状态 public class EveningState : State { public override void WriteProgram(Work w) { if (w.TaskFinished) { w.SetState(new RestState()); w.WriteProgram(); } else { if (w.Hour < 21) { Console.WriteLine("当前时间{0}点 加班额 疲劳至极", w.Hour); } else { w.SetState(new SleepingState()); w.WriteProgram(); } } } } //睡眠状态 public class SleepingState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间{0}点 不行了 睡着了", w.Hour); } } //下班休息状态 public class RestState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间{0}点 下班回家了", w.Hour); } } //工作类 public class Work { private State Current; public Work() { Current = new ForenoonState(); } private double hour; public double Hour { get { return hour; } set { hour = value; } } private bool finish = false; public bool TaskFinished { get { return finish; } set { finish = value; } } public void SetState(State s) { Current = s; } public void WriteProgram() { Current.WriteProgram(this); } } class Program { static void Main(string[] args) { //紧急项目 Work emergencyProjects = new Work(); emergencyProjects.Hour = 9; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 10; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 12; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 13; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 14; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 17; emergencyProjects.TaskFinished = false; emergencyProjects.Hour = 19; emergencyProjects.WriteProgram(); emergencyProjects.Hour = 22; emergencyProjects.WriteProgram(); Console.ReadKey(); } } }
输出结果如下所示:
以上的代码,如果要增加一项,员工必须在20点之前下班,只需要增加一个'强制下班状态',并改动'傍晚工作状态'就可以了,而不影响其他状态的代码。