建議149:使用表驅動法避免過長的if和switch分支

建議149:使用表驅動法避免過長的if和switch分支

隨着代碼變得複雜,我們很容易被過長的if和switch分支困擾。

一個類枚舉類型Week如下:

複製代碼
    enum Week
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }
複製代碼

 如果要把Week的元素值用中文輸出,簡單而醜陋的方法也許是封裝一個GetChineseWeek方法:

複製代碼
        static string GetChineseWeek(Week week)
        {
            switch (week)
            {
                case Week.Monday:
                    return "星期一";
                case Week.Tuesday:
                    return "星期二";
                case Week.Wednesday:
                    return "星期三";
                case Week.Thursday:
                    return "星期四";
                case Week.Friday:
                    return "星期五";
                case Week.Saturday:
                    return "星期六";
                case Week.Sunday:
                    return "星期日";
                default:
                    throw new ArgumentOutOfRangeException("week","星期值超出範圍");
            }
        }
複製代碼

 

 之所以說這種方法太醜陋,是因爲:

1)分支太長了,而且出現了重複代碼。

2)不利於擴展。如果出現星期八、星期九怎麼辦?當然,星期制已經是固定的了,應該不會出現擴展情況。但是,換種情景來考慮,假設我們正在渲染動畫怎麼辦?誰知道下一秒美工會提交我多少個動畫呢?

一種解決方案是使用多態,它很好的符合了“開閉”原則。如果增加條件分支,不必修改源代碼,直接增加子類就可以了。利用多態避免分支,這裏暫且不表,本建議要採用的是“表驅動法”。

可以把表驅動簡單理解爲查字典。代碼如下表示:

複製代碼
        static string GetChineseWeek(Week week)
        {
            string[] chineseWeek = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" };
            return chineseWeek[(int) week];
        }

        static void Main(string[] args)
        {
            Console.WriteLine(GetChineseWeek(Week.Friday));
        }
複製代碼

 這是一種按照索引值驅動的表驅動法。枚舉元素代表的整型值,很容易和字符串數組索引結合起來,用兩行語句就解決了GetChineseWeek方法。但是,這種方法有侷限性,如果需要換成:星期一Mike打掃衛生、星期二Rose清理衣櫃、星期三Mike和Rose沒事可以吵吵架、星期四Rose要去Shopping,也就是說需求由靜態屬性變成了動態行爲,那麼事情就變得複雜了。

遇上這種情況,我們可能會想到使用多態,在這裏依然使用表驅動法加上一點反射來實現這類動態的行爲,代碼如下:

複製代碼
    class Program
    {
        static string ActionInTable(Week week)
        {
            string[] methods = { "Cleaning", "CleanCloset", "Quarrel", "Shopping", "Temp", "Temp", "Temp" };
            return methods[(int)week];
        }

        static void Main(string[] args)
        {
            SampleClass sample=new SampleClass();
            var addMethod = typeof (SampleClass).GetMethod(ActionInTable(Week.Monday));
            addMethod.Invoke(sample, null);
        }
    }

    class SampleClass
    {
        public void Cleaning()
        {
            Console.WriteLine("打掃");
        }
        public void CleanCloset()
        {
            Console.WriteLine("整理衣櫥");
        }
        public void Quarrel()
        {
            Console.WriteLine("吵架");
        }
        public void Shopping()
        {
            Console.WriteLine("購物");
        }
        public void Temp()
        {
            Console.WriteLine("臨時安排");
        }
    }
複製代碼

表驅動法是一種設計思路,也可以稱爲模式。在實際編碼中,不應侷限於用索引去驅動行爲,而應當根據實際情況靈活運用。

 

 

轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章