iT邦幫忙

DAY 9
7

如何提升系統設計品質 - 技術與工具以.NET為例系列 第 9

[如何提升系統品質-Day9]重構-簡化判斷式

前面提到了許多篇重構的方式,都是偏向pattern或較大面向的設計重構,在面對比較大的系統包袱時,或許大家比較沒法子運用的得心應手,所以接下來會穿插一些誰都可以進行重構的技巧,希望讓大家對改善系統能更有衝動。

重構通常針對的就是兩個東西:判斷式與迴圈。這一篇文章會提到,怎麼樣重構我們的判斷式,使其更容易閱讀,更具備未來修改的彈性。

[如何提升系統品質]系列文章連結
範例說明
很無聊的在腦袋中,哼著『戲鳳』這首歌,稍微調整了一下,就變成了我們重構的目標了。程式碼如下:

/// <summary>
/// idea from :戲鳳, http://www.youtube.com/watch?v=JRs_bqW39oA
/// </summary>
public class DrinkingStore
{
    public Person Boss { get; set; }

    public bool IsBusinessDay(DateTime date, Person customer)
    {
        //一三五不賣酒
        if (date.DayOfWeek == DayOfWeek.Monday || date.DayOfWeek == DayOfWeek.Wednesday || date.DayOfWeek == DayOfWeek.Friday ||
            //初一十五不賣酒
            date.Day == 1 || date.Day == 15 ||
            //老闆不爽不賣酒, 老闆哥哥不在家不賣酒
            this.Boss.IsAngry || this.Boss.Brother == null ||
            //客人沒錢不賣酒//客人太醜不賣酒//客人太胖不賣酒
            customer.IsPoor || customer.IsUgly || customer.IsFat)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

可以看到程式中,一個if判斷式,裡面要判斷的條件落落長,而且這種條件判斷,很常修改或新增其他新的需求。第一版的程式,可能只有寫『哥哥不在家,今天不賣酒』,隨著情況越來越多,程式經手越來越多人,最後程式就長這樣。

當我們看到這樣的程式,你可以選擇:
反正現在的程式活的好好的,不要去改他。前人都這樣加上去,我們就跟著這樣加上去。
一塊一塊的抽出來,沒有動到架構,我有100%信心把這一段程式寫的更人性化且不會衍生問題。

看完這篇文章,希望大家都可以勇敢的選2!

重構步驟
步驟一:
首先,我們先抽象地瞭解這個function要提供什麼功能。
1.根據條件來決定,賣不賣酒
2.條件有分成幾種類型:
(1)根據『日期中的星期幾』來決定
(2)根據『日期中的日子』來決定
(3)根據『老闆的一堆毛』來決定
(4)根據『客人的一堆毛』來決定

步驟二:
根據我們剛剛分析的第二點,一項一項把我們的條件拆開。

調整完的程式碼:

/// <summary>
    /// idea from :戲鳳, http://www.youtube.com/watch?v=JRs_bqW39oA
    /// </summary>
    public class DrinkingStore
    {
        public Person Boss { get; set; }

        public bool IsBusinessDay(DateTime date, Person customer)
        {
            if (WithoutSellingByDayOfWeek(date) ||
                WithoutSellingByDay(date) ||
                WithoutSellingByBoss() ||
                WithoutSellingByCustomer(customer))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 一三五不賣酒
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        private static bool WithoutSellingByDayOfWeek(DateTime date)
        {
            return date.DayOfWeek == DayOfWeek.Monday || date.DayOfWeek == DayOfWeek.Wednesday || date.DayOfWeek == DayOfWeek.Friday;
        }

        /// <summary>
        /// 初一十五不賣酒
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        private static bool WithoutSellingByDay(DateTime date)
        {
            return date.Day == 1 || date.Day == 15;
        }

        /// <summary>
        /// 老闆不爽不賣酒, 老闆哥哥不在家不賣酒
        /// </summary>
        /// <returns></returns>
        private bool WithoutSellingByBoss()
        {
            return this.Boss.IsAngry || this.Boss.Brother == null;
        }

        /// <summary>
        /// 客人沒錢不賣酒
        /// 客人太醜不賣酒
        /// 客人太胖不賣酒
        /// </summary>
        /// <returns></returns>
        private bool WithoutSellingByCustomer(Person customer)
        {
            return customer.IsPoor || customer.IsUgly || customer.IsFat;
        }
    }

步驟三:
因為這個例子的判斷式裡面,因素有點多,為了可讀性,我會再宣告幾個變數來接各個情況回傳的bool值。透過bool變數的命名,會讓判斷式看起來更容易瞭解意思。

步驟四:
最後,因為我們這個function也是要回傳bool,所以可以連最後一個if都直接拿掉。

這樣我們的function,跟重構前的程式比起來,有沒好讀很多? 不管那些條件是不是一堆or跟一堆and交錯,最後都可以將判斷式簡化成比較抽象地概念。

當抽象完成後,未來如果是還有其他條件加進來,我們可以看該條件是否可以歸在已經定好的分類,來決定要新增一個bool跟function,或直接新增在原有的function中。這樣一來,最高階的IsBusinessDay的function,就不容易因為條件細節而需要一直變動。當出現問題或需求異動時,我們也可以很快速的調整設計。

結論
雖然只是簡單的判斷式重構,但這一招真的是簡單好用,可以用很小的成本,馬上讓原本花撒撒的程式變乾淨。

另外要提醒的一點是,if的判斷式裡面,就不要再出現判斷某個bool變數、bool屬性或function回傳bool值是 == true或== false了,因為bool就代表了true/false,就可以直接用來套上判斷式的意義。


上一篇
[如何提升系統品質-Day8]重構-抽象來看程式是否符合DRY原則
下一篇
[如何提升系統品質-Day10]重構-合併重複的條件片段
系列文
如何提升系統設計品質 - 技術與工具以.NET為例30
0
billchung
iT邦新手 3 級 ‧ 2011-10-19 07:02:15

嗚嗚嗚...有時候就是懶啊..

就是91 iT邦研究生 4 級 ‧ 2011-10-19 09:48:01 檢舉

哈,我的原則是事不過三,第一次可以懶,第二次可以只修,第三次就要避免問題或需求異動一直發生了。複製貼上也是,一式兩份還在容許範圍,三份就代表有問題了

0
chiounan
iT邦研究生 1 級 ‧ 2011-10-19 09:38:58

讚期待您的下一篇分享

就是91 iT邦研究生 4 級 ‧ 2011-10-19 09:48:43 檢舉

感謝!謝謝

0
pantc328
iT邦研究生 1 級 ‧ 2011-10-19 10:49:27

坦白說沒達到效果
我以前也會這樣做
但每個老闆,夥伴,使用者概念不同
最後我覺得在程序式裡直接寫,人家一看就懂較易維護
有些人不喜歡程式跳來跳去的或寫一些幫助的方法
有些人不喜歡OO你要看Code要跳來要去還要一層一層的看
除非整個Team有共識
不然就用最白痴,最直覺的方式做
反正也沒幾行Code

就是91 iT邦研究生 4 級 ‧ 2011-10-19 12:16:39 檢舉

這就是每個人的想法不同。
對我來說,如果上頭要的是具備彈性的架構,『好維護的架構』。
那其他成員不懂這種基本的趨勢跟技能,是他們失職。

沒必要一起爛,也沒必要為了自己一己之私去推什麼最新的技術或framework。

但我得說,也沒幾行code是你碰到的個案,就是有這種理由,所以才會需要這麼多重構的文章。
若您覺得重構跟OO都是沒必要的,我建議您這系列文章都不需要看囉,對您來說都是垃圾。您就繼續維持最白痴的作法,或許對您是最好的。

pantc328 iT邦研究生 1 級 ‧ 2011-10-20 08:57:13 檢舉

我沒有否定你,也沒有叫人否定你
如果你認為大家的想法都要跟你一樣,你就別PO了
重構的方式非常多種
OO是一種
有人重構
是讓Code更少
有人是為效能
有人為可讀性
有人為可維護性
....

這麼沒什麼在那裡P來P去,那毫無意義
一支程式
不同的規模,不同的功用,不同的主管,不同的客戶..就會有不同的評價
如果你是寫不同企業的程式,他們就會規定你們的寫法。有人規範要全部寫在一個檔,有的要切多層..

鐵殼心 iT邦高手 1 級 ‧ 2011-10-20 09:19:21 檢舉

pantc328提到:
有人重構
是讓Code更少
有人是為效能
有人為可讀性
有人為可維護性

每家公司的要求是不一樣的...

0
billchung
iT邦新手 3 級 ‧ 2011-10-19 12:29:50

我笑了ㄟ...怎麼有人講話老是顛三倒四的呢 ?

0
billchung
iT邦新手 3 級 ‧ 2011-10-22 01:02:37

樓主, 你是一個被人挖角去外商的人才, 何必在意一個總是只會抱怨找不到工作的人講的話呢.

我要留言

立即登入留言