講故事
彩虹環繞這秋香、春香、夏香,秋香、春香、夏香環繞著我,這時鍵盤飛入我的懷中(小朋友,你是否有許多的問號),飛速的敲擊鍵盤,不一會兒婀娜多姿的冬香也出現在我的面前,
有了四大美人相伴,那我的生活要好好重新安排一下,早上誰來服侍我,中午誰來服侍我,下午誰來服侍我,晚上誰來服侍我,想想都美啊~
安排...
Coding
Time 、Weather 時間段和天氣列舉
/// <summary> /// 時間段 /// </summary> public enum Time { Morning, Noon, Afternoon, Night } /// <summary> /// 天氣 /// </summary> public enum Weather { /// <summary> /// 好天氣 /// </summary> Good, /// <summary> /// 壞天氣 /// </summary> Bad }
Life類,模擬一天的生活,根據不同時間段來判斷誰來服侍我干什么
/// <summary> /// 生活 /// </summary> public class Life { /// <summary> /// 時間段 /// </summary> public Time Time { get; set; } /// <summary> /// 天氣 /// </summary> public Weather Weather { get; set; } /// <summary> /// 干啥子 /// </summary> public void Doing() { if (Time == Time.Morning) { Console.WriteLine($"\n現在是 早上,春香 服侍我起床~"); } else if (Time == Time.Noon) { Console.WriteLine($"\n現在是 中午,夏香 陪我玩耍~"); if (Weather == Weather.Good) { Console.WriteLine($"天氣真好,陪我出去放風箏"); } else { Console.WriteLine($"天氣不好,待家給我跳舞"); } } else if (Time == Time.Afternoon) { Console.WriteLine($"\n現在是 下午,秋香 服侍我用餐~"); } else if (Time == Time.Night) { Console.WriteLine($"\n現在是 晚上,冬香 服侍我就寢~"); } else { Console.WriteLine($"\n睡覺中..."); } } }
客戶端 開始我一天的生活
internal class Program
{
private static void Main(string[] args)
{
var life = new Life();
//設定天氣
life.Weather = Weather.Good;
life.Time = Time.Morning;
life.Doing();
life.Time = Time.Noon;
life.Doing();
life.Time = Time.Afternoon;
life.Doing();
life.Time = Time.Night;
life.Doing();
Console.WriteLine("\nHappy Ending~");
Console.ReadLine();
}
}
結果展示:
現在是 早上,春香 服侍我起床~
現在是 中午,夏香 陪我玩耍~
天氣真好,陪我出去放風箏
現在是 下午,秋香 服侍我用餐~
現在是 晚上,冬香 服侍我就寢~
結果還是挺美好的,但是 這個實作程序很是糟糕,
尤其是Life.Doing()
/// <summary>
/// 干啥子
/// </summary>
public void Doing()
{
if (Time == Time.Morning)
{
Console.WriteLine($"\n現在是 早上,春香 服侍我起床~");
}
else if (Time == Time.Noon)
{
Console.WriteLine($"\n現在是 中午,夏香 陪我玩耍~");
if (Weather == Weather.Good)
{
Console.WriteLine($"天氣真好,陪我出去放風箏");
}
else
{
Console.WriteLine($"天氣不好,待家給我跳舞");
}
}
else if (Time == Time.Afternoon)
{
Console.WriteLine($"\n現在是 下午,秋香 服侍我用餐~");
}
else if (Time == Time.Night)
{
Console.WriteLine($"\n現在是 晚上,冬香 服侍我就寢~");
}
else
{
Console.WriteLine($"\n睡覺中...");
}
}
這個方法存在以下問題:
- 方法很長(如果我們再把時間段細分以下,或者每個時間段做的事情增加,實際開發中,可能每個判斷中包含很多很復雜的業務邏輯),開發程序中,我們要盡量保持每個方法體代碼行數不超過50行,
- 判斷分支太多,if else很多,并且還存在嵌套,該方法的責任過大,同時也不方便閱讀,
- 維護困難,以后要增加時間段,比如我 想在深夜 有人來服侍我吃宵夜,要修改Life.Doing()來實作,這完全違背了我的人生信條的第3條!
如何解決上面的問題呢?這時房中升起了四個金光閃閃的大字——狀態模式
狀態模式
敲黑板·劃重點
定義: 當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類,(上面案例中,時間段Time就是Life物件的狀態,當Time改變時,Life的行為Doing()就改變了)
作用: 主要解決當控制一個物件狀態轉換條件運算式過于復雜時的情況,把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把復雜的判斷邏輯簡化,
好處: 將與特定狀態相關的行為區域化,并且將不同狀態的行為分割開來,
思想: 將特定狀態相關的行為都放入一個物件中,由于所有與狀態相關的代碼都存在于具體的狀態物件中,所以通過定義新的子類就可以很容易地增加新的狀態和轉換,消除龐大的條件分支陳述句,通過把各種狀態轉移邏輯分布到狀態的子類之間,來減少相互間的依賴,
解決方法已經找到,就開始干吧...
Code Upgrade
ITimeHandle介面,定義各種時間段(狀態)的行為,
public interface ITimeHandle { /// <summary> /// 干啥子 /// </summary> /// <param name="life"></param> public void Doing(Life life); }
Life類,屬性中包含ITimeHandle,行為Doing()交個具體的時間段操作(狀態物件),
/// <summary> /// 生活 /// </summary> public class Life { private ITimeHandle _timeHandle; /// <summary> /// 時間段 /// </summary> public Time Time { get; set; } /// <summary> /// 天氣 /// </summary> public Weather Weather { get; set; } /// <summary> /// 初始化 一天生活的 時間段 /// </summary> public Life() { //默認設定時間為 上午 _timeHandle = new MorningTime(); } /// <summary> /// 設定時間段對應的操作類 /// </summary> /// <param name="timeHandle"></param> public void SetTimeHandle(ITimeHandle timeHandle) { _timeHandle = timeHandle; } /// <summary> /// 干啥子 /// </summary> public void Doing() { _timeHandle.Doing(this); } }
MorningTime、NoonTime、AfternoonTime、NightTime類實作ITimeHandle介面(這也就是 思想 中:將與特定狀態相關的行為區域化,所有與狀態相關的代碼都存在于具體的狀態物件中),在具體的時間段類中來判斷改該做什么(這也就是 作用 中:把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把復雜的判斷邏輯簡化),
/// <summary> /// 早上 干什么 /// </summary> public class MorningTime : ITimeHandle { public void Doing(Life life) { if (life.Time == Time.Morning) { Console.WriteLine($"現在是 早上,春香 服侍我起床~"); } else { life.SetTimeHandle(new NoonTime()); life.Doing(); } } } /// <summary> /// 中午 干什么 /// </summary> public class NoonTime : ITimeHandle { public void Doing(Life life) { if (life.Time == Time.Noon) { Console.WriteLine($"現在是 中午,夏香 陪我玩耍~"); if (life.Weather == Weather.Good) { Console.WriteLine($"天氣真好,陪我出去放風箏"); } else { Console.WriteLine($"天氣不好,待家給我跳舞"); } } else { life.SetTimeHandle(new AfternoonTime()); life.Doing(); } } } /// <summary> /// 下午 干什么 /// </summary> public class AfternoonTime : ITimeHandle { public void Doing(Life life) { if (life.Time == Time.Afternoon) { Console.WriteLine($"現在是 下午,秋香 服侍我用餐~"); } else { life.SetTimeHandle(new NightTime()); life.Doing(); } } } /// <summary> /// 晚上 干什么 /// </summary> public class NightTime : ITimeHandle { public void Doing(Life life) { if (life.Time == Time.Night) { Console.WriteLine($"現在是 晚上,冬香 服侍我就寢~"); } else { Console.WriteLine($"睡覺中..."); } } }
客戶端代碼 和 輸出結果 同上
現在,我們再來看看Life.Doing()
/// <summary>
/// 干啥子
/// </summary>
public void Doing()
{
_timeHandle.Doing(this);
}
方法簡潔明了,消除了過多的判斷分支,
同時Life類的職責簡化了,做到代碼的責任分解,符合了我人生信條的第1條和第3條,
這時候,我們再要增加一個深夜吃夜宵的時間段,Life類就不需要動了,我們只需增加WeeHoursTime類實作ITimeHandle,調整NightTime中的判斷就可以了,
吟詩
糟糕的問題完美解決,我心啥訓,吟詩一首:
桃花塢里桃花庵,
桃花庵下桃花仙,
桃花仙人敲代碼,
桃花運來年復年,
示例代碼地址: https://gitee.com/sayook/DesignMode/tree/master/State
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/12574.html
標籤:設計模式
