《代码大全2》之---高质量的子程序设计

来源:互联网 发布:淘宝卖家发布不了宝贝 编辑:程序博客网 时间:2024/04/30 02:46

第一部分 高质量子程序设计

 

本文为《代码大全2》的读书笔记,版权归代码大全所有。^_^

本文基址: http://blog.csdn.net/cugxueyu/archive/2007/12/10/1926703.aspx

·      创建子程序的正当理由

·      在子程序层上的设计

·      好的子程序名字

·      子程序可以写多长

·      如何使用子程序参数

·      使用函数时要特别考虑的问题

·      宏子程序和内联子程序

 

※ 子程序定义:为实现一个特定的目的而编写的一个可被调用的方法或过程

低质量的子程序

>    差劲的子程序名字

>    没有文档

>    代码布局不好

>    子程序没有一个单一的目的

>    没有错误处理

>    使用神秘数据(没有意义的单纯数字)

>    参数过多

>    参数顺序混乱且未经注释

子程序也是迄今为止用以节约空间和提高性能的最重要手段

※ 创建一个子程序可以有很多合理的原因,但完成它的方法却有对错之分

 

1、  创建子程序的正当理由

>    降低复杂度

  隐藏代码细节、缩小代码规模、改善可维护性、提高正确性。

  如果没有子程序的抽象能力,我们的智力水平将无法管理复杂的程序

  如:当内部循环条件判断的嵌套层次很深时,就需要把嵌套的部分提取出来形成一个独立的子程序,可以降低外围子程序的复杂度

 

>    引入中间、易懂的抽象

  把一段代码放入一个命名恰当的子程序内,是说明这段代码用意最好的方法之一。

 

  ※ 提供了更高层次的抽象,从而使代码更具可读性,也更容易理解,同时也降低了调用代码的复杂度。

 

>    避免代码重复

  ※ 创建子程序最主要的原因:避免代码重复。

  ※ 如果两个子程序内编写了相同或相似的代码,就意味着代码分解失败了。

  ※ 节约存储空间、改动起来方便可靠、有利于验证代码正确。

 

>    支持子类化

  ※ 覆盖简短而规整的子程序所需新代码的数量,要比覆盖冗长而邋遢的子程序更少。

  ※ 如果能让可覆盖的子程序保持简单,那你在实现派生类的时候也会减小出错的几率。

 

>    隐藏顺序

  ※ 隐藏处理事件的顺序。

  ※ 如:pop_statck()  à 先读取栈顶的数据,然后减少stackTop变量的值。

 

>    隐藏指针操作

  ※ 把指针操作隔离在子程序内部,可以把精力集中于业务本身,而不是指针操作机制的细节。

  ※ 益处:集中指针操作(提高正确性)。

 

>    提高可移植性

  ※ 可以使用子程序来隔离不可移植的部分

  不可移植:语言提供的非标准特型、对硬件和操作系统的依赖。

 

>    简化复杂的布尔判断

  ※ 布尔判断的逻辑放入单独的函数中,也强调了它的重要性,这样也会激励程序员在函数内部做出更多的努力,提高代码的可读性。

 

>    改善性能

  ※ 采用子程序,可以只在一个地方优化代码

  ※ 可以更方便的查找出效能低下的代码、可以用高效的算法和快速语言来容易得替换代码。

 

>    确保所有的子程都很小

  ※ 使代码的结构更容易掌握

 

2、  在子程序层上的设计

  内聚性:指子程序中,各种操作之间联系的紧密程度。(抽象和封装基本已经取代内聚性)

  目标:让每一个子程序指把一件事情做好,不再做任何其他事情。

 

  理解一些概念要比记住一些特定的术语更重要(出发原则)

>    功能的内聚性

  ※ 是最强也是最好的一种内聚性,也就是说,让一个子程序仅仅执行一项操作

  评估内聚性:前提是子程序所执行的操作与其名字相符。

 

>    顺序上的内聚性

  ※ 指在子程序内,包含有需要按特定顺序执行的操作,这些步骤需要共享数据,而且只有在全部执行完毕后才完成一项完整的功能。

 

>    通信上的内聚性

     ※ 指一个子程序的不同操作使用了同样的数据通信媒介),但不存在任何其他的联系。

>    临时的内聚性

  ※ 指含有一些因为需要同时执行才放到一起的操作的子程序。

  例如:start_up()子程序可能需要读取配置文件、初始化临时文件、设置内存管理器等。

  术语没有哪个是神秘的或者神圣不可侵犯的,需要理解的是其中的想法,而不是那些术语把注意力集中于功能上的内聚性上)。

 

3、  好的子程序名字

※ 好的子程序的名字能清晰地描述子程序所做的一切。

 指导规则

>    描述子程序所做的所有事情

>    避免使用无意义的,模糊或表述不清的动词

>    不要仅通过数字来形成不同的子程序名字

>    根据需要确定子程序名字的长度(视该名字是否清晰易懂而定)

>    给函数命名时要对返回值有所描述

>    给过程起名时使用语气强烈的动词加宾语的形式

>    准确使用对仗语(add/remove等)

>    为常用操作确立命名规则用于区分不同类别的操作

 

4、  子程序可以写多长

  ※ 理论上认为:子程序最佳最大长度通常是一屏代码或打印出来一到两页的代码,大约50-150行代码。(IBM 50行之内。 TRW: 两页纸之内。)

  ※ 与其对子程序的长度强加限制,还不如让下面这些因素来决定子程序的长度

  (子程序的内聚性、嵌套的层次、变量的数量、决策点的数量、解释子程序用意的注释数量以及跟复杂度相关的考虑事项)。

 

5、  如何使用子程序参数

  子程序之间的接口是程序中最易出错的部分之一。

    减少接口间错误的指导原则

>    按照输入-修改-输出的顺序排列参数

  Wrong随机、按字母顺序

  ※ 顺序参考:仅作为输入参数 à 既是输入又是输出的参数 à 仅作为输出的参数

 

>    考虑自己创建INOUT关键字

  ※ 预处理定义INOUT(起说明性作用)

  ※ 注意:1、确保一致的使用该定义方法。2、不要混淆IN和const的作用。

 

>    如果几个子程序都用了类似的一些参数,应该让这些参数的排列顺序保持一致

  例:fprintf()/printffputs/putsstrncpy/memcpy

 

>    使用所有的参数

  往一个子程序中传递一个参数,就一定要使用这个参数。如果你不要它,请尽快把它从接口中删除。

 

>    把状态和出错变量放在参数表最后

  ※ 它们只是附属于程序的主要功能,而且它们是仅用于输出的变量

 

>    不要把子程序的参数用做工作变量

  ※ 请明确的引入工作变量

>    在接口中对参数的假定加以说明

  ※ 如果假定了传递给子程序的参数具有某种特征,那就要对这种假定加以说明

  ※ 一种比用注释还好的方法 —> 在代码中使用断言

 

 应该对哪些接口参数的假定说明:

  ※ 参数是仅用于输入的、要被修改的、还是仅用于输出的。

  ※ 表示数量的参数的单位(英寸、英尺、米等)。

  状态代码和错误值的含义

  ※ 接受的数值的范围。

  ※ 不该出现的特定数值。

 

>    把子程序的参数个数限制在大约7个以内

>    考虑对参数采用某种表示输入、修改、输出的命名规则

  ※ 认为区分输入、修改、输出参数很重要的话,就建立一种命名规则来进行区分。

 

>    为子程序传递用以维护其接口抽象的变量或对象

  ※ 如果要表达的抽象是:子程序期望3项特定数据,这3项数据碰巧由同一个对象提供,那就应单独传递3项数据。

  ※ 如果要表达的抽象是:想一直拥有某个特定的对象,且要对这个对象执行很多操作,就应该传递整个对象。

 

>    使用具名参数

  Visual Basic:可以显式地把形式参数和实际参数对应起来。

 

>    确保实际参数和形式参数相匹配

  好习惯:总要检查参数表中参数的类型,同时留意编译器给出的关于参数类型不匹配的警告。

 

6、  使用函数时要特别考虑的问题

  函数(有返回值的子程序)和过程(无返回值的子程序)的区别更多的是语义的区被,而不是语法的区别。

>    什么时候使用函数,什么时候使用过程

>    设置函数的返回值

  回避返回错误的返回值的原则:

  ※ 检查所有可能的返回路径(尽可能初始化返回值

  ※ 不要返回值向局部数据的饮用或指针。

 

7、  宏子程序和内联子程序

  预处理器的宏语言编写的指导原则:

  ※ 把宏表达式整个包含在括号内

    (最终要展开到代码中:#define CUBE(a) ((a) * (a) * (a))

  ※ 把含有多条语句的宏用大括号括起来

   

    使用宏函数具有风险、且不易理解,应该尽量避免使用

  ※ 用给子程序命名的方式来个宏函数命名,以便在需要时可以用子程序来替换它

  宏子程序在使用上的限制(C++语言替代宏的方案)

   1const定义常量

   2inline定义内嵌代码函数

   3template用于以类型安全的方式定义各种标准操作,minmax

   4typedef可以定义简单的类型替换

 

  ※ 内联子程序

   因为避免了子程序调用的开销,因此inline机制可以产生高效的代码。

   ※ 节制使用inline子程序

     inline子程序违反了封装原则,实现代码写在头文件中,从而暴露了程序的实现细节

原创粉丝点击