狀態模式(State),當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。javascript
狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的狀況,把狀態的判斷邏輯轉到到表示不一樣狀態的一系列類當中,能夠把複雜的邏輯判斷簡化。固然,若是這個狀態的判斷很簡單,就沒有必要使用狀態模式了。html
若是我沒理解錯的話,說白了就是若是判斷很長,就把判斷分割到多個類裏面。java
狀態模式的好處是將與特定狀態相關的行爲局部化,而且將不一樣狀態的行爲分隔開來。狀態模式經過吧各類狀態轉移邏輯分佈到State子類之間,來減小相互間的依賴。git
問:何時考慮使用狀態模式呢?設計模式
答:當一個對象的行爲取決於它的狀態,而且它必須在運行時刻根據狀態改變它的行爲時,就能夠考慮使用狀態模式了。ide
爲何要叫狀態模式呢?由於狀態是會變更的,改變狀態又改變了行爲。post
來看下狀態模式的UML圖:學習
狀態模式的代碼結構:this
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(); } } }
輸出結果以下:spa
回到《大話設計模式》中的上班的例子:
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點以前下班,只須要增長一個'強制下班狀態',並改動'傍晚工做狀態'就能夠了,而不影響其餘狀態的代碼。