代码大全——第四部分

来源:互联网 发布:java中判断质数 编辑:程序博客网 时间:2024/05/16 04:31

第四部分是关于语句的,分别谈了顺序、条件和循环语句以及一些特殊结构如递归、goto等,最后是使用表驱动的方法(把判断存于表中)和一些一般问题。

顺序执行的代码分成两种,一种是“有明确顺序的语句”也就是有先后依赖关系的语句,另一种是“顺序无关的语句”无依赖关系的语句。依赖关系往往很难避免,但应设法使依赖关系变得明显,如将子程序功能明确并具有好的名字,使用合理的参数,同样的参数往往可以暗示存在数据关系。断言、注释都可以成为理清顺序关系的重要方法。对于顺序无关的语句应满足自上而下的阅读顺序,并把相关语句组织在一起(变量的使用也是,减少变量生存时间)也可以将相关语句组成子程序。

条件语句主要有if和switch,对于if语句,应该在条件中放置正常的条件(或者是常见的条件),如if(老师在学校)then 。。。使用正条件往往要比负条件好,但也不是绝对的 ,如if(不换课)then。。。 因为这种情况也是可以的,因为不换课是正常情况,需要首先处理。then后面应该跟一个有意义的语句,这也是检验上面条件的好方法,因为作为条件语句中的正常情况,就应该有适当处理。如果不做处理,就不应该是正常情况,或者就不应该用判断语句。最差的解决方法就是写个空函数doNothing();这用在else子句中是个更可取的方法,以表明else情况已被考虑,并不应该做什么事情。利用布尔函数来简化复杂的条件,过长或过于复杂的条件判断会使程序很难读懂,用一个命名准确的bool函数可以起到很好的作用。
case语句是对if-else语句的简化,就像? :对if语句的简化一样,都不是很全面的,如c++和java只支持在case中使用整数,C#支持整数和string。不要为了使用switch而使用switch,使用一些特殊的表达方式的时候也就意味着灵活性和可扩充性的缩小,所以只有在数值分类、固定条件比较情况下使用,并且在固定条件比较时,故意造一个变量出来,以适应switch也不是一个好的做法,这使得语句没有了语义。switch中的default应该留给错误检查,而不是处理正常情况,这也就是不要使用错误处理机制来处理正常情况,如果使用try catch和throw来处理正常情况,那更是一件极端错误事件。

循环控制是一种更上一步的控制结构,它其实包含顺序执行语句和条件语句(一般循环都是要退出条件的)。使用for还是while,我觉得还是一个习惯问题。但对于统一编程习惯来说,还是应该规范起来。我个人比较习惯于使用for循环,可能是因为它比较“强大”,至少while能做到的for都能,除了do-while方式。但for多出来的初始定义、和条件增加两项滥用之后也会存在问题。如把这两项都去掉,这完全是一个while方式。最适合for情况的就是遍历数组这种指定长度的方式,而且初试条件和条件增加正好可以用来实现脚标的初始化和增加,后来的foreach也是遵循这个思想。而对于遍历链表的情况可以使用while,也可以使用for。但这都不是关键,关键在于不要滥用for。退出循环可以使用多个出口,但入口一定只能有一个,通过goto方式进入while循环将是件很麻烦的事情。如果在while或for条件中作为入口也是唯一的出口可以有助于模块中的模块化,这样就可以把循环作为一个黑盒来出来,可能不需要知道循环中的处理方式,如果多出口(使用exit do,break)就表明更多的可能结果,也需要我们去了解循环中的具体操作。空循环就像if then后面没有语句一样不被推荐,在for中既然是循环就可能有其用途,将这些用途写在for循环体中,而不是在for的括号里面,或许这是精彩独到的写法,同时也意味着读懂它需要更多的时间。循环变量应该遵循一般变量使用的规则,如缩小生存周期,使用有意义的名字,使其只有一个用途等等。java、c#和c++都支持在循环模块中定义循环变量,把循环变量的使用范围局限于循环体中,这是一个不错的习惯,但在c中不能如此。循环变量应该使用整数或者枚举类型,浮点数会导致不确定后果。使用浮点数出来精确的整数增量计算是会出问题的。循环变量名字使用i,j,k是通用简单的方法,但有时候也可以使用一些具有特定语义的词语来增加可读性。但个人认为在循环变量不是很多,情况并不是很复杂的情况下,使用i,j也就足够了。因为作为英文非母语的国家,使用英文所带来的好处没有母语国家带来带来的好处明显,并且处理脚标和循环变量这种常常用到点变量,使用i,j单字母方式会是代码简洁很多。通过伪代码的方式,从问题本质出发来导出具体写法。也就是“由内而外”的写循环方式。

子程序的多处返回有点象循环中的break,过多的return和过多的break一样使程序混乱。但适当的使用又是必需的。递归的使用更要谨慎,对于非必要情况不应该使用递归。如计算斐波纳数等情况,但在遍历树和图时又是一种很优雅的使用方式。同时也要注意,计算机中栈要比堆空间宝贵,使用new在堆上分配空间,而不是通过参数在栈上分配空间。goto语句应该归为一种高级应用,在没有深入了解它之前应该尽量避免。许多高级语言也在使用如try-catch等方法来规范化程序,寻找goto应用的好的替代品。

表驱动方法让我想起了数据库,其实在程序之间嵌入数据并不是很好的做法,即使对已判断,判断条件也是可能变的,如果因为条件的变而要修改代码,似乎过于麻烦。当然这不是表驱动的初衷,它最大的好处在于简化判断语句,使程序结构更加清晰。如何将条件转换为表是一种技术,可以直接设计访问表(直接的,区间的等)也可以索引表(稀疏数据)阶梯访问表也是一种区间的表达方式。

最后一章《一般控制问题》对前面的问题进行了总结和再次描述。如用bool型来做判断语句,这在java和C#中已经避免了使用0和非0作为判断条件的可行性,这有助于清晰判断条件。肯定的布尔型判断也在前面提到,但要和常用和一般条件做一个折衷。有时候否定的条件才是正真常用的条件。条件的表达式应该以数轴区间的方式来表达。对于多层次的语句,应该使用break块,case语句,编写单独子程序的方法来减少语句层次,多于4层的嵌套就会比较难理解。

原创粉丝点击