1.什么是子程序?子程序是为实现一个特定的目的而编写的一个可被调用的方法或过程。
2.创建子程序的理由:
- a.降低复杂度:这里的降低复杂度并不是指降低程序的时间复杂度,而是指降低代码的复杂度。比如当内部循环或者条件判断的嵌套层次很深时,把嵌套部分提取出来形成一个独立的子程序,可以降低外围子程序的复杂度。
- b.引入中间,易懂的抽象:把一段代码放入一个命名恰当的子程序内,可以很好的说明代码的意图
- c.避免代码重复:这是众所周知的原因
- d.隐藏顺序:有时候把一些事件的顺序隐藏起来是很好的;比如你写两行代码,一行读取栈顶数据,然后减少stackTop变量的值,把这两行代码放到一个pop子程序中隐藏起执行顺序比让他们在系统内到处分散要好很多。
- e.隐藏指针操作:用c语言的程序员都知道指针操作的危险性,通过把这些操作隔离在子程序内部,可以很好的避免指针操作出错的危险
- f.提高可移植性:这个也是众所周知
- g.简化复杂的布尔判断:当你主要关注程序的流程时,通常没有必要去研究那些复杂的布尔判断细节,把这些放入函数中,可以提高代码的可读性。
- h.改善性能:通过使用子程序,可以只在一个地方优化代码,把代码集中在一处还可以更方便的查处那些代码的效率低下。
除此之外还有很多其他的理由比如:隔离复杂度,隐藏实现细节,限制变化带来的影响,隐藏全局数据,形成中央控制点,促成可重用代码,达到特定的重构牧的等等。
在子程序层上设计:
内聚性:指子程序中各种操作之间联系的紧密程度。我们的目标应该是让每一个子程序只把一件事做好不再做任何其他的事情。
关于内聚性的概念可以涉及到几个层次:
- 1)功能的内聚性:这是最强也是最好的内聚性,也就是说让子程序仅执行一项操作。
- 2)顺序的内聚性:指在子程序内包含有需要按特定顺序执行的操作,这些步骤需要共享数据,而且只有在全部执行完后才完成一项完整的功能。
- 3)通信上的内聚性:是指一个字程序中的不同操作使用了同样的数据,但不存在其他任何的联系。
- 4)临时的内聚性:指含有一些因为需要同时执行才放到一起的操作的子程序。
一般来说除了功能的内聚性其他层次上的内聚性都是不可取的,当然这是对最完美的子程序的要求。另外还有一些应该被抛弃的内聚性:
- 过程上的内聚性:指一个子程序中的操作时按特定顺序进行的
- 逻辑上的内聚性:是指若干操作被放入同一个子程序中通过传入的标志选择执行其中的一项操作,尽管很多大的系统中都使用了这一内聚性
- 巧合的内聚性:指子程序中的各个操作之间没有任何的联系虽然有时候编写功能上的内聚性的子程序很困难,但是一个优秀的程序员应该把注意力集中在功能上的内聚性,从而获得最大的收获。
子程序的名字:
- 好的字程序名字应该能清晰的描述子程序所作的一切,下面列出一些有效的指导原则:描述程序所作的事情;变面使用无意义的,模糊或表述不清的动词;必要仅通过数字来形成不同的子程序名字;明明时应该对返回值有所描述;准确适用对仗词;为常用操作确立命名规则
子程序的长度:理论上认为子程序最佳最大长度通常是一屏代码或者打印出来的一道两页的代码,也即50-150行,研究表明100-150行代码的子程序需要被修改的几率最低。当子程序长度超过200行的时候我们就因该小心了。
如何使用子程序的参数:
下面是一些避免参数出错的指导原则:
- 按照输入-修改-输出的顺序排列参数,这是一个很好的方式,特别是当参数数目较多时
- 如果几个子程序使用了类似的一些参数,应该让这些参数的排列顺序保持一致:当你遇到这样的情况的时候就知道这一建议很有用。
- 把状态或出错变量放在最后不要把子程序的参数用作工作变量把子程序的参数个数限制在大约7个以内考虑采
- 用某种表示输入,修改,输出的命名规则为子程序传递用以维持其接口抽象的变量或对象:例如我们拥有一个包含10个数据的对象,而子程序需要访问其中的三个参数,我们到底是该传送对象的三个变量呢还是把整个对象传过去?这一问题很不好回答,该问题的答案取决于子程序接口要表达何种抽象?如果要表达的抽象是子程序期望3项特定的数据,但这3项数据只是碰巧由同一个对象所提供,那就应该单独传递三项数据,然而如果子程序接口要表达的抽象是想一直拥有某个特定对象,且该子程序要对这一对象执行一些操作,就应该传递真个对象。
- 确保形参和实参相匹配:这应该是一种良好的编程习惯
对于宏子程序的一些建议:
- 把宏表达式真个包含在括号内;把含有多条语句的宏用大括号括起来,不过C++中通常可以用inline函数替代宏
- inline子程序的限制:应该节制使用inline子程序,因为子程序违反了封装原则,因为C/C++要求把inline子程序的实现代码写在头文件中,从而把这些实现细节暴露给了所有使用该头文件的程序员