结构化编程的三重境界:见山不是山:正确但冗余的逻辑

简介:

因此我们了解到,我们需要更加精确的判断时间的界限。因此我们重新将代码改为如下:

 
  1. static void Main(string[] args)  
  2. {  
  3.  
  4.     DateTime indate = new DateTime(2008, 9, 30);                    //入住时间  
  5.     DateTime outdate = new DateTime(2008, 10, 5, 12, 15, 12);        //退房时间  
  6.     double days = (outdate - indate).Days;                        //计算入住了几天  
  7.  
  8.     if (outdate.Hour <= 11)                                    //这个时间段是 0:0:0到11:59:59  
  9.     {  
  10.         days += 0;                                            //当天不计算房费  
  11.     }  
  12.     else 
  13.     {                            //如果小时部分的值是12,且其的分秒部分的值都是0,就是12点整  
  14.         if (outdate.Hour == 12 && outdate.Minute == 0 && outdate.Second == 0)   
  15.         {  
  16.             days += 0;                                        //当天也不计算房费  
  17.         }  
  18.         else//12:0:0以后  
  19.         {  
  20.             if (outdate.Hour <= 17)                                //时间段为 12:0:1到17:59:59  
  21.             {  
  22.                 days += 0.5;                                    //加收半天房费  
  23.             }  
  24.             else                                            //18点之后  
  25.             {                        //如果小时部分的值是18,且其的分秒部分的值都是0,就是18点整                                                  
  26.                 if (outdate.Hour == 18 && outdate.Minute == 0 && outdate.Second == 0)   
  27.                 {  
  28.                     days += 0.5;                            //加收半天房费  
  29.                 }  
  30.                 else 
  31.                 {//18点之后  
  32.                     days++;                                //加收一天房费  
  33.                 }  
  34.             }  
  35.         }  
  36.     }  
  37.     System.Console.WriteLine("你的入住结算信息/n入住时间{0}/n退房时间{1}/n一共入住了{2}天", indate, outdate, days);  
  38. }  

上述的代码,使用了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

完全可以函数化,因此我们需要添加一个函数模块。

 
  1. /// <summary>  
  2. /// 判断给定的时间是否是一个整时  
  3. /// </summary>  
  4. /// <param name="date">需要判断的时间</param>  
  5. /// <returns>如果是整时,则返回true,否则返回false</returns>  
  6. static bool IsZeroTime(DateTime date)  
  7. {  
  8.     if (date.Minute == 0 && date.Second == 0)//如果给定的时间的分秒值都是0  
  9.     {  
  10.         return true;  
  11.     }  
  12.     else 
  13.     {  
  14.         return false;  
  15.     }  
  16. }  

我们新编写的IsZeroTime将判断整时的问题进行了函数(模块)化,不过初学的人要注意一点,如果一个if else 中仅处理一个问题的时候,我们完全可以优化成如下代码

 

 
  1. /// <summary>  
  2. /// 判断给定的时间是否是一个整时  
  3. /// </summary>  
  4. /// <param name="date">需要判断的时间</param>  
  5. /// <returns>如果是整时,则返回true,否则返回false</returns>  
  6. static bool IsZeroTime(DateTime date)  
  7. {  
  8.     return date.Minute == 0 && date.Second == 0;  
  9. }  

现在我们再来修改原先的逻辑主体的代码为:

 
  1. static void Main(string[] args)  
  2. {  
  3.  
  4.     DateTime indate = new DateTime(2008, 9, 30);                //入住时间  
  5.     DateTime outdate = new DateTime(2008, 10, 5, 12, 15, 12);    //退房时间  
  6.     double days = (outdate - indate).Days;                    //计算入住了几天  
  7.  
  8.     if (outdate.Hour <= 11)                                //这个时间段是 0:0:0到11:59:59  
  9.     {  
  10.         days += 0;                                        //当天不计算房费  
  11.     }  
  12.     else 
  13.     {  
  14.         if (outdate.Hour == 12 && IsZeroTime(outdate))            //如果是12点整  
  15.         {  
  16.             days += 0;                                    //当天也不计算房费  
  17.         }  
  18.         else//12:0:0以后  
  19.         {  
  20.             if (outdate.Hour <= 17)                            //时间段为 12:0:1到17:59:59  
  21.             {  
  22.                 days += 0.5;                                //加收半天房费  
  23.             }  
  24.             else 
  25.             { //18点之后  
  26.                 if (outdate.Hour == 18 && IsZeroTime(outdate))    //如果是18点整  
  27.                 {  
  28.                     days += 0.5;                            //加收半天房费  
  29.                 }  
  30.                 else 
  31.                 {                                        //18点之后  
  32.                     days++;                                //加收一天房费  
  33.                 }  
  34.             }  
  35.         }  
  36.     }  
  37.     System.Console.WriteLine("你的入住结算信息/n入住时间{0}/n退房时间{1}/n一共入住了{2}天", indate, outdate, days);  
  38. }  

以上代码使用了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小时算一天,否则算半天;如果顾客是隔天退房,那还继续保持我们原有的逻辑处理。

 
  1. static void Main(string[] args)  
  2. {  
  3.  
  4.     DateTime indate = new DateTime(2008, 10, 5, 19, 12, 0);        //入住时间  
  5.     DateTime outdate = new DateTime(2008, 10, 5, 19, 13, 0);        //退房时间  
  6.  
  7.     double days = (outdate.Date - indate.Date).Days;            //计算入住了几天  
  8.  
  9.     if (days == 0)  
  10.     {                                                //同天退房  
  11.         if ((outdate - indate).TotalHours <= 12)                //入住时间不超过12小时  
  12.         {  
  13.             days += 0.5;                                    //以半天房费计算  
  14.         }  
  15.         else                                            //超过12小时  
  16.         {  
  17.             days++;                                    //计算一天的房费  
  18.         }  
  19.     }  
  20.     else 
  21.     {                                                //隔夜退房  
  22.  
  23.         if (outdate.Hour <= 11)                            //这个时间段是 0:0:0到11:59:59  
  24.         {  
  25.             days += 0;                                    //当天不计算房费  
  26.         }  
  27.         else 
  28.         {  
  29.             if (outdate.Hour == 12 && IsZeroTime(outdate))        //如果是12点整  
  30.             {  
  31.                 days += 0;                                //当天也不计算房费  
  32.             }  
  33.             else                                        //12:0:0以后  
  34.             {  
  35.                 if (outdate.Hour <= 17)                        //时间段为 12:0:1到17:59:59  
  36.                 {  
  37.                     days += 0.5;                            //加收半天房费  
  38.                 }  
  39.                 else 
  40.                 {                                         //18点之后  
  41.                     if (outdate.Hour == 18 && IsZeroTime(outdate))    //如果是18点整  
  42.                     {  
  43.                         days += 0.5;                        //加收半天房费  
  44.                     }  
  45.                     else 
  46.                     {                                    //18点之后  
  47.                         days++;//加收一天房费  
  48.                     }  
  49.                 }  
  50.             }  
  51.         }  
  52.     }  
  53.     System.Console.WriteLine("你的入住结算信息/n入住时间{0}/n退房时间{1}/n一共入住了{2}天", indate, outdate, days);  
  54. }  

现在我们可以处理同天退房和隔夜退房的不同逻辑了,我们可以看到,通过精确的控制,我们的代码可处理的能力越来越强大,不过代码也越来越复杂了,嵌套也越来越庞大。因此,我们开始反思,为了追求正确的逻辑,我们是不是走了太远了?



本文转自shyleoking 51CTO博客,原文链接:http://blog.51cto.com/shyleoking/805178

相关文章
|
1月前
|
存储 机器学习/深度学习 算法
【魔法编程奇谭】:探秘C语言递归的“时空轮回术”
【魔法编程奇谭】:探秘C语言递归的“时空轮回术”
|
1月前
|
C++
逻辑智力题
二进制问题 1、1000瓶药水找毒药(一) 问题: 有 1000 个一模一样的瓶子,其中有 999 瓶是普通的水,有一瓶是毒药。任何喝下毒药的生物都会在一星期之后死亡。现在,你只有 10 只小白鼠和一星期的时间,如何检验出哪个瓶子里有毒药? 解析: 二进制思想:首先一共有1000瓶药水,给每瓶药水编号:1,2,3,4,5,6...1000,2的10次方是1024,刚好大于1000, 也就是说,1000瓶药水可以使用10位二进制数来表示。 如下: 毒药在第一瓶:00 0000 0001 毒药在第二瓶:00 0000 0010 毒药在第三瓶:00 0000 0100 ....... 毒药在第999
|
设计模式 开发框架 JSON
了解这些软件设计思想,你的思维至少上升一个段位
在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念,四位作者合称 GOF(全拼 Gang of Four),简称四人帮!
|
算法 Shell 决策智能
只用一行代码就能搞定,博弈论究竟是什么神仙算法?
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 博弈论是一门很庞大的学科,它算是数学的一个分支,也和运筹学甚至是经济学有关。虽然它严格说起来并不是算法领域的内容,但是有不少关于博弈论有趣的算法和问题。
【逻辑题】是谁在说谎?
有五兄弟,各说了一句话:老大说:我们五人中,有一个人正在撒谎。老二说:我们五人中,有两个人在撒谎。老三说:我们五人中,有三个人撒谎。老四说:我们五人中,有四人撒谎。老五说:我们五个人全都在撒谎。
2128 0
|
测试技术 数据中心