什麼是狀態者模式? 每個對象都有其對應的狀態,而每個狀態又對應一些相應的行為,如果某個對象有多個狀態時,那麼就會對應很多的行為。那麼對這些狀態的判斷和根據狀態完成的行為,就會導致多重條件語句,並且如果添加一種新的狀態時,需要更改之前現有的代碼。這樣的設計顯然違背了開閉原則。狀態模式正是用來解決這樣的 ...
什麼是狀態者模式?
每個對象都有其對應的狀態,而每個狀態又對應一些相應的行為,如果某個對象有多個狀態時,那麼就會對應很多的行為。那麼對這些狀態的判斷和根據狀態完成的行為,就會導致多重條件語句,並且如果添加一種新的狀態時,需要更改之前現有的代碼。這樣的設計顯然違背了開閉原則。狀態模式正是用來解決這樣的問題的。狀態模式將每種狀態對應的行為抽象出來成為單獨新的對象,這樣狀態的變化不再依賴於對象內部的行為。
狀態者模式:當一個對象的內在狀態改變時允許改變其行為,這個對象看起來像是改變了其類。其主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的情況。通過把狀態的判斷邏輯轉移到表示不同的一系列類當中,可以把複雜的邏輯判斷簡單化。
- 上下文環境(Context):它定義了客戶程式需要的介面並維護一個具體狀態角色的實例,將與狀態相關的操作委托給當前的Concrete State對象來處理。
- 抽象狀態(State):定義一個介面以封裝使用上下文環境的的一個特定狀態相關的行為。
- 具體狀態(Concrete State):實現抽象狀態定義的介面。
設計思路及代碼實現
/// <summary> /// Context類,維護一個ConcreteState子類的實例,這個實例定義當前的狀態。 /// </summary> public class Context { private State state; /// <summary> /// 定義Context的初始狀態 /// </summary> /// <param name="state"></param> public Context(State state) { this.state = state; } /// <summary> /// 可讀寫的狀態屬性,用於讀取和設置新狀態 /// </summary> public State State { get { return state; } set { state = value; } } /// <summary> /// 對請求做處理,並設置下一個狀態 /// </summary> public void Request() { state.Handle(this); } } /// <summary> /// 抽象狀態類,定義一個介面以封裝與Context的一個特定狀態相關的行為 /// </summary> public abstract class State { public abstract void Handle(Context context); } /// <summary> /// 具體狀態類,每一個子類實現一個與Context的一個狀態相關的行為 /// </summary> public class ConcreteStateA : State { /// <summary> /// 設置ConcreteStateA的下一個狀態是ConcreteStateB /// </summary> /// <param name="context"></param> public override void Handle(Context context) { Console.WriteLine("當前狀態是 A."); context.State = new ConcreteStateB(); } } /// <summary> /// 具體狀態類,每一個子類實現一個與Context的一個狀態相關的行為 /// </summary> public class ConcreteStateB : State { /// <summary> /// 設置ConcreteStateB的下一個狀態是ConcreteSateA /// </summary> /// <param name="context"></param> public override void Handle(Context context) { Console.WriteLine("當前狀態是 B."); context.State = new ConcreteStateA(); } } /// <summary> /// 調用 /// </summary> /// <param name="args"></param> static void Main(string[] args) { // 設置Context的初始狀態為ConcreteStateA Context context = new Context(new ConcreteStateA()); // 不斷地進行請求,同時更改狀態 for (int i = 0; i < 10; i++) { context.Request(); } Console.ReadLine(); }
應用狀態者模式完善中介者模式
/// <summary> /// 抽象牌友類 /// </summary> public abstract class AbstractCardPartner { public int Money { get; set; } public abstract void ChangeMoney(int money, AbstractMediator mediator); } /// <summary> /// 牌友A /// </summary> public class PartnerA : AbstractCardPartner { public override void ChangeMoney(int money, AbstractMediator mediator) { mediator.ChangeMoney(money); } } /// <summary> /// 牌友B /// </summary> public class PartnerB : AbstractCardPartner { public override void ChangeMoney(int money, AbstractMediator mediator) { mediator.ChangeMoney(money); } } // 抽象狀態類 public abstract class State { protected AbstractMediator meditor; public abstract void ChangeMoney(int money); } // 初始化狀態類 public class InitState : State { public InitState() { Console.WriteLine("游戲才剛剛開始,暫時還有玩家勝出"); } public override void ChangeMoney(int money) { return; } } public class AWinState : State { public AWinState(AbstractMediator concretemediator) { meditor = concretemediator; } public override void ChangeMoney(int money) { foreach (AbstractCardPartner p in meditor.list) { PartnerA a = p as PartnerA; if (a != null) { a.Money += money; } else { p.Money -= money; } } } } public class BWinState : State { public BWinState(AbstractMediator concretemediator) { meditor = concretemediator; } public override void ChangeMoney(int money) { foreach (AbstractCardPartner p in meditor.list) { PartnerB b = p as PartnerB; // 如果集合對象中時B對象,則對B的錢添加 if (b != null) { b.Money += money; } else { p.Money -= money; } } } } /// <summary> /// 抽象中介者類 /// </summary> public abstract class AbstractMediator { public List<AbstractCardPartner> list = new List<AbstractCardPartner>(); public State State { get; set; } public AbstractMediator(State state) { State = state; } public void Add(AbstractCardPartner partner) { list.Add(partner); } public void Remove(AbstractCardPartner partner) { list.Remove(partner); } public void ChangeMoney(int money) { State.ChangeMoney(money); } } /// <summary> /// 中介者Pater /// </summary> public class MediatorPater : AbstractMediator { public MediatorPater(State state) : base(state) { } } /// <summary> /// 調用 /// </summary> /// <param name="args"></param> static void Main(string[] args) { State.Mediator.AbstractCardPartner A = new State.Mediator.PartnerA(); State.Mediator.AbstractCardPartner B = new State.Mediator.PartnerB(); // 初始錢 A.Money = 20; B.Money = 20; State.Mediator.AbstractMediator mediator = new State.Mediator.MediatorPater(new State.Mediator.InitState()); // A,B玩家進入平臺進行游戲 mediator.Add(A); mediator.Add(B); // A 贏了 mediator.State = new State.Mediator.AWinState(mediator); mediator.ChangeMoney(5); Console.WriteLine("A 現在的錢是:{0}", A.Money);// 應該是25 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 // B 贏了 mediator.State = new State.Mediator.BWinState(mediator); mediator.ChangeMoney(10); Console.WriteLine("A 現在的錢是:{0}", A.Money);// 應該是25 Console.WriteLine("B 現在的錢是:{0}", B.Money); // 應該是15 Console.ReadLine(); }
狀態者模式優缺點
優點:
- 將狀態判斷邏輯每個狀態類裡面,可以簡化判斷的邏輯。
- 當有新的狀態出現時,可以通過添加新的狀態類來進行擴展,擴展性好。
缺點: 如果狀態過多的話,會導致有非常多的狀態類,加大了開銷
狀態者模式適用場景
在以下情況下可以考慮使用狀態者模式。
- 當一個對象狀態轉換的條件表達式過於複雜時可以使用狀態者模式。把狀態的判斷邏輯轉移到表示不同狀態的一系列類中,可以把複雜的判斷邏輯簡單化。
- 當一個對象行為取決於它的狀態,並且它需要在運行時刻根據狀態改變它的行為時,就可以考慮使用狀態者模式。