天天看點

結構化程式設計的三重境界:見山不是山:正确但備援的邏輯

是以我們了解到,我們需要更加精确的判斷時間的界限。是以我們重新将代碼改為如下:

static void Main(string[] args)  

{  

    DateTime indate = new DateTime(2008, 9, 30);                    //入住時間  

    DateTime outdate = new DateTime(2008, 10, 5, 12, 15, 12);        //退房時間  

    double days = (outdate - indate).Days;                        //計算入住了幾天  

    if (outdate.Hour <= 11)                                    //這個時間段是 0:0:0到11:59:59  

    {  

        days += 0;                                            //當天不計算房費  

    }  

    else 

    {                            //如果小時部分的值是12,且其的分秒部分的值都是0,就是12點整  

        if (outdate.Hour == 12 && outdate.Minute == 0 && outdate.Second == 0)   

        {  

            days += 0;                                        //當天也不計算房費  

        }  

        else//12:0:0以後  

            if (outdate.Hour <= 17)                                //時間段為 12:0:1到17:59:59  

            {  

                days += 0.5;                                    //加收半天房費  

            }  

            else                                            //18點之後  

            {                        //如果小時部分的值是18,且其的分秒部分的值都是0,就是18點整                                                  

                if (outdate.Hour == 18 && outdate.Minute == 0 && outdate.Second == 0)   

                {  

                    days += 0.5;                            //加收半天房費  

                }  

                else 

                {//18點之後  

                    days++;                                //加收一天房費  

    System.Console.WriteLine("你的入住結算資訊/n入住時間{0}/n退房時間{1}/n一共入住了{2}天", indate, outdate, days);  

}  

上述的代碼,使用了4個條件的嵌套判斷,将退房的時間作了精确的判斷(考慮到了分秒的臨界點),同時初學的人員再次要了解到注釋的重要性,以上的邏輯,如果不描寫注釋,估計過一個月後,你自己都不知道自己在幹什麼了。

現在我們運作程式,設定以下的時間段

DateTime indate = new DateTime(2008, 9, 30); //入住時間

DateTime outdate = new DateTime(2008, 10, 5, 12, 15, 12); //退房時間

我們程式的運作結果得到了我們樂于見到的5.5天

結構化程式設計,還有一個重要的概念就是子產品化,我們上面的代碼中對整點的判斷。比如12點整

outdate.Hour == 12 && outdate.Minute == 0 && outdate.Second == 0

和18點整

outdate.Hour == 18 && outdate.Minute == 0 && outdate.Second == 0

完全可以函數化,是以我們需要添加一個函數子產品。

/// <summary>  

/// 判斷給定的時間是否是一個整時  

/// </summary>  

/// <param name="date">需要判斷的時間</param>  

/// <returns>如果是整時,則傳回true,否則傳回false</returns>  

static bool IsZeroTime(DateTime date)  

    if (date.Minute == 0 && date.Second == 0)//如果給定的時間的分秒值都是0  

        return true;  

        return false;  

我們新編寫的IsZeroTime将判斷整時的問題進行了函數(子產品)化,不過初學的人要注意一點,如果一個if else 中僅處理一個問題的時候,我們完全可以優化成如下代碼

    return date.Minute == 0 && date.Second == 0;  

現在我們再來修改原先的邏輯主體的代碼為:

    DateTime indate = new DateTime(2008, 9, 30);                //入住時間  

    DateTime outdate = new DateTime(2008, 10, 5, 12, 15, 12);    //退房時間  

    double days = (outdate - indate).Days;                    //計算入住了幾天  

    if (outdate.Hour <= 11)                                //這個時間段是 0:0:0到11:59:59  

        days += 0;                                        //當天不計算房費  

        if (outdate.Hour == 12 && IsZeroTime(outdate))            //如果是12點整  

            days += 0;                                    //當天也不計算房費  

            if (outdate.Hour <= 17)                            //時間段為 12:0:1到17:59:59  

                days += 0.5;                                //加收半天房費  

            else 

            { //18點之後  

                if (outdate.Hour == 18 && IsZeroTime(outdate))    //如果是18點整  

                {                                        //18點之後  

以上代碼使用了IsZeroTime函數,讓代碼的表現能力更強更優雅。那現在是不是萬事大吉呢了?我們現在看看以下的時間:

DateTime indate = new DateTime(2008, 10, 5, 2, 12, 0);//入住時間

DateTime outdate = new DateTime(2008, 10, 5, 12, 0, 0);//退房時間

我們的程式告訴我們,顧客住了0天!!!

而以下的日期

DateTime indate = new DateTime(2008, 10, 5, 19, 12, 0); //入住時間

DateTime outdate = new DateTime(2008, 10, 5, 19, 13, 0); //退房時間

我們的程式告訴我們,顧客住了1天!!!

啊,那是多麼不公平的事情啊,一個住了近10個小時的人計算機竟然說他可以免費,而另一個住了才1分鐘的顧客,竟然要支付整整一天的房價!

問題出在哪裡呢?如果你仔細想想,就可以猜到,我們一開始的計算也許就錯了。

double days = (outdate - indate).Days; //計算入住了幾天

原來這個Days不是計算過了幾個晚上,而是兩個時間的間隔,該間隔用納秒來計算出。是以我們要使用內插補點來計算使用者是不是過夜的話,不能簡單的進行相減。不過如果我們使用些技巧就可以來解決,比如我們把兩個時間都切換到午夜時間(就是午夜兇鈴那個電話鈴響的時間,0:0:0),那麼就可以計算機出使用者是否過夜了。

double days = (outdate.Date - indate.Date).Days; //計算入住了幾天

這樣的話,隻要顧客不是同天退房,就會得到大于0的值,如果值是0就表示使用者是同天退房的。如果使用者是隔夜退房的,我們的邏輯計算照舊,否則要看看使用者住的時間是否超過半天。這樣才合理嘛。

是以,我們需要把代碼作些小的調正,先判斷下顧客是否同天退房,如果是同天退房的話,計算他入住了幾個小時:超過12小時算一天,否則算半天;如果顧客是隔天退房,那還繼續保持我們原有的邏輯處理。

    DateTime indate = new DateTime(2008, 10, 5, 19, 12, 0);        //入住時間  

    DateTime outdate = new DateTime(2008, 10, 5, 19, 13, 0);        //退房時間  

    double days = (outdate.Date - indate.Date).Days;            //計算入住了幾天  

    if (days == 0)  

    {                                                //同天退房  

        if ((outdate - indate).TotalHours <= 12)                //入住時間不超過12小時  

            days += 0.5;                                    //以半天房費計算  

        else                                            //超過12小時  

            days++;                                    //計算一天的房費  

    {                                                //隔夜退房  

        if (outdate.Hour <= 11)                            //這個時間段是 0:0:0到11:59:59  

            days += 0;                                    //當天不計算房費  

        else 

            if (outdate.Hour == 12 && IsZeroTime(outdate))        //如果是12點整  

                days += 0;                                //當天也不計算房費  

            else                                        //12:0:0以後  

                if (outdate.Hour <= 17)                        //時間段為 12:0:1到17:59:59  

                {                                         //18點之後  

                    if (outdate.Hour == 18 && IsZeroTime(outdate))    //如果是18點整  

                    {  

                        days += 0.5;                        //加收半天房費  

                    }  

                    else 

                    {                                    //18點之後  

                        days++;//加收一天房費  

現在我們可以處理同天退房和隔夜退房的不同邏輯了,我們可以看到,通過精确的控制,我們的代碼可處理的能力越來越強大,不過代碼也越來越複雜了,嵌套也越來越龐大。是以,我們開始反思,為了追求正确的邏輯,我們是不是走了太遠了?

本文轉自shyleoking 51CTO部落格,原文連結:http://blog.51cto.com/shyleoking/805178

繼續閱讀