設計模式(19)狀態模式
阿新 • • 發佈:2018-12-21
模式介紹
狀態模式旨在允許物件在其內部狀態改變時改變其自身行為。
示例
我們以烤牛排為例,生熟程度分為:
- Uncooked (not safe to eat)
- Rare
- Medium-Rare (mid-rare)
- Medium
- Medium-Well (mid-well)
- Well done
簡單來說就是從生到熟的幾個檔次。
抽象的狀態類:
/// <summary> /// The State abstract class /// </summary> abstract class Doneness { protected Steak steak; protected double currentTemp; protected double lowerTemp; protected double upperTemp; protected bool canEat; public Steak Steak { get { return steak; } set { steak = value; } } public double CurrentTemp { get { return currentTemp; } set { currentTemp = value; } } public abstract void AddTemp(double temp); public abstract void RemoveTemp(double temp); public abstract void DonenessCheck(); }
具體的狀態類:
/// <summary> /// A Concrete State class. /// </summary> class Uncooked : Doneness { public Uncooked(Doneness state) { currentTemp = state.CurrentTemp; steak = state.Steak; Initialize(); } private void Initialize() { lowerTemp = 0; upperTemp = 130; canEat = false; } public override void AddTemp(double amount) { currentTemp += amount; DonenessCheck(); } public override void RemoveTemp(double amount) { currentTemp -= amount; DonenessCheck(); } public override void DonenessCheck() { if (currentTemp > upperTemp) { steak.State = new Rare(this); } } } /// <summary> /// A 'ConcreteState' class. /// </summary> class Rare : Doneness { public Rare(Doneness state) : this(state.CurrentTemp, state.Steak) { } public Rare(double currentTemp, Steak steak) { this.currentTemp = currentTemp; this.steak = steak; canEat = true; //We can now eat the steak Initialize(); } private void Initialize() { lowerTemp = 130; upperTemp = 139.999999999999; canEat = true; } public override void AddTemp(double amount) { currentTemp += amount; DonenessCheck(); } public override void RemoveTemp(double amount) { currentTemp -= amount; DonenessCheck(); } public override void DonenessCheck() { if (currentTemp < lowerTemp) { steak.State = new Uncooked(this); } else if (currentTemp > upperTemp) { steak.State = new MediumRare(this); } } } /// <summary> /// A Concrete State class /// </summary> class MediumRare : Doneness { public MediumRare(Doneness state) : this(state.CurrentTemp, state.Steak) { } public MediumRare(double currentTemp, Steak steak) { this.currentTemp = currentTemp; this.steak = steak; canEat = true; Initialize(); } private void Initialize() { lowerTemp = 140; upperTemp = 154.9999999999; } public override void AddTemp(double amount) { currentTemp += amount; DonenessCheck(); } public override void RemoveTemp(double amount) { currentTemp -= amount; DonenessCheck(); } public override void DonenessCheck() { if (currentTemp < 0.0) { steak.State = new Uncooked(this); } else if (currentTemp < lowerTemp) { steak.State = new Rare(this); } else if (currentTemp > upperTemp) { steak.State = new Medium(this); } } } /// <summary> /// A Concrete State class /// </summary> class Medium : Doneness { public Medium(Doneness state) : this(state.CurrentTemp, state.Steak) { } public Medium(double currentTemp, Steak steak) { this.currentTemp = currentTemp; this.steak = steak; canEat = true; Initialize(); } private void Initialize() { lowerTemp = 155; upperTemp = 169.9999999999; } public override void AddTemp(double amount) { currentTemp += amount; DonenessCheck(); } public override void RemoveTemp(double amount) { currentTemp -= amount; DonenessCheck(); } public override void DonenessCheck() { if (currentTemp < 130) { steak.State = new Uncooked(this); } else if (currentTemp < lowerTemp) { steak.State = new MediumRare(this); } else if (currentTemp > upperTemp) { steak.State = new WellDone(this); } } } /// <summary> /// A Concrete State class /// </summary> class WellDone : Doneness //aka Ruined { public WellDone(Doneness state) : this(state.CurrentTemp, state.Steak) { } public WellDone(double currentTemp, Steak steak) { this.currentTemp = currentTemp; this.steak = steak; canEat = true; Initialize(); } private void Initialize() { lowerTemp = 170; upperTemp = 230; } public override void AddTemp(double amount) { currentTemp += amount; DonenessCheck(); } public override void RemoveTemp(double amount) { currentTemp -= amount; DonenessCheck(); } public override void DonenessCheck() { if (currentTemp < 0) { steak.State = new Uncooked(this); } else if (currentTemp < lowerTemp) { steak.State = new Medium(this); } } }
上下文類-牛排:
/// <summary> /// The Context class /// </summary> class Steak { private Doneness _state; private string _beefCut; public Steak(string beefCut) { _cook = beefCut; _state = new Rare(0.0, this); } public double CurrentTemp { get { return _state.CurrentTemp; } } public Doneness State { get { return _state; } set { _state = value; } } public void AddTemp(double amount) { _state.AddTemp(amount); Console.WriteLine("Increased temperature by {0} degrees.", amount); Console.WriteLine(" Current temp is {0}", CurrentTemp); Console.WriteLine(" Status is {0}", State.GetType().Name); Console.WriteLine(""); } public void RemoveTemp(double amount) { _state.RemoveTemp(amount); Console.WriteLine("Decreased temperature by {0} degrees.", amount); Console.WriteLine(" Current temp is {0}", CurrentTemp); Console.WriteLine(" Status is {0}", State.GetType().Name); Console.WriteLine(""); } }
客戶端呼叫:
static void Main(string[] args)
{
//Let's cook a steak!
Steak account = new Steak("T-Bone");
// Apply temperature changes
account.AddTemp(120);
account.AddTemp(15);
account.AddTemp(15);
account.RemoveTemp(10); //Yes I know cooking doesn't work this way, bear with me.
account.RemoveTemp(15);
account.AddTemp(20);
account.AddTemp(20);
account.AddTemp(20);
Console.ReadKey();
}
總結
狀態模式允許物件的行為隨著其內部狀態的改變而改變,並且它通過使物件的狀態與物件本身分開來完成這一任務。 因此,狀態可以為物件實現它們自己的行為,並且物件可以對其內部狀態改變作出“反應”。