如何编写高质量的子程序<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
原文:《代码大全2》 整理:METAL MAX 时间:2008年10月07日
子程序:
它是为实现一个特定的目的而编写的一个可被调用的方法(method)或过程(procedure)。
高质量的子程序
要点:
1. 创建子程序的主要目的是提高程序的可管理性,当然也有其他一些好的理由。其中,节省代码空间只是一个次要原因;提供可读性、可靠性和可修改性等原因更重要一些;
2. 有时候,把一些简单的操作写成独立的子程序也非常有价值;
3. 子程序可以按照其内聚性分为很多类,而你应该让大多数子程序具有功能上的内聚性,这是最佳的一种内聚性;
4. 子程序的名字是其质量的指示器。如果名字糟糕但恰如其分,那就说明这个程序设计得很差劲。如果名字糟糕而且又不准确,那么它就反映不出程序是干什么的。不管怎样,糟糕的名字都意味着程序需要修改;
5. 只有在某个子程序的主要目的是返回由其名字所描述的特定结果时,才应该使用函数;
6. 细心的程序员会非常谨慎地使用宏,而且只是在万不得已时采用。
如何判定高质量的子程序
大局上的:
1. 创建子程序的理由充分码?
2. 一个子程序中所有适合单独提出作为子程序的部分是否已经全部提取出?
3. 过程的名字是否用了强烈、清晰的“动词+宾语”词组?函数的名字是否描述了其返回值?
4. 子程序的名字是否描述了它所做的全部事情?
5. 是否给常用的操作建立了命名规则?
6. 子程序是否具有强烈的功能上的内聚性?即它是否做且只做了一件事,并且把它做得很好?
7. 子程序之间是否有较松的耦合?子程序与其他子程序之间的连接是否是小的(small)、明确(intimate)、可见的(available)和灵活(flexible)?
8. 子程序的长度是否由其功能和逻辑自然确定,而非遵循任何人为的编码标准?
参数传递事宜:
1. 整体来看,子程序的参数表是否出现一种具有整体性且一致的接口抽象?
2. 子程序参数的排列顺序是否合理?是否与类似的子程序的参数排列顺序相符?
3. 接口假定是否已在文档中说明?
4. 子程序的参数格式是否没超过7个?
5. 是否用到了每一个输入参数?
6. 是否用到了每一个输出参数?
7. 子程序是否避免了把输入参数作为工作变量?
8. 如果子程序是一个函数,那么它是否在所有可能的情况下都能返回一个合法的值?
创建子程序的正当理由:
1. 避免代码重复;
2. 支持子类化;
3. 隐藏顺序;
4. 隐藏指针操作;
5. 提高可移植性;
6. 简化复杂的布尔判断;
7. 改善性能。
除此以外,创建类的很多理由也是创建子程序的理由:
1. 隔离复杂度;
2. 隐藏实现细节;
3. 限制变化所带来的影响;
4. 隐藏全局数据;
5. 形成中央控制点;
6. 促成可重用的代码;
7. 达到特定的重构目的。
注意:编写一个有效的子程序时,一个最大的心理障碍是不情愿为一个简单的目的而编写一个简单子程序。写一个只有两三行代码的子程序可能看起来有些大材小用,但经验可以表明,一个很好的又小巧的子程序会多有用。
内聚性
1. 功能的内聚性;
2. 顺序上的内聚性;
3. 通信上的内聚性;
4. 临时的内聚性;
5. 过程上的内聚性;
6. 逻辑上的内聚性;
7. 巧合的内聚性。
注意:编写具有功能上的内聚性的子程序总是可能的,因此把注意力集中于功能上的内聚性,从而得到最大的收获。
好的子程序名字
1. 描述子程序所做的所有事情;
2. 避免使用无意义、模糊或表述不清的动词;
3. 不要仅通过数字来形成不同的子程序名字;
4. 根据需要确定子程序名字的长度;
5. 给函数命名时要对返回值有所描述;
6. 给过程取名时使用语气强烈的动词加宾语形式;
7. 准确使用对仗词;
8. 为常用操作确立命名规则。
子程序最佳长度
1. 推荐200行以内;
2. 理论上认为的子程序最佳长度通常为一屏代码或者打印出来一到两页的代码,约50~150行;
如何使用子程序参数
1. 按照输入-修改-输出的顺序排列参数;
2. 考虑使用自己创建IN和OUT关键字;
3. 如果几个子程序都用了类似的一些参数,应该让这些参数的排列顺序保持一致;
4. 使用所有参数;
5. 把状态或出错变量放在最后;
6. 不要把子程序的参数用作工作变量;
7. 在接口中对参数的假定加以说明;
8. 把子程序的参数个数限制在大约7个以内;
9. 考虑对参数采用某种能标识输入、输出、修改特性的命名规则;
10. 为子程序传递用以维持其接口抽象的变量或对象;
11. 使用具名参数;
12. 确保实际参数与形式参数相匹配。
什么时候使用函数,什么时候使用过程
语言纯化论者们认为,一个函数应该只有一个返回值,就像数学函数一样。这就意味着函数只能接受仅用于输入的参数,并只通过函数本身返回一项结果。
函数用以应该以它所返回的值来命名,就像sin(),CustomerID(),ScreenHeight()一样。在另外一个方面,过程则可以根据所需,接受任意数量的输入、修改和输出参数。
简而言之,如果一个子程序的主要用途就是返回由其名字所指明的返回值,那么就应该使用函数,否则就应该使用过程。
设置函数的返回值
1. 检查所有可能的返回路径;
2. 不要返回指向局部bianl 的引用或指针。
宏子程序和内联子程序
1. 把宏表达式整个包含在括号内;
2. 把含有多条语句的宏用大括号括起来;
3. 用给子程序命名的方式给展开后代码形同子程序的宏命名,以便在需要时可以用子程序替换宏
宏子程序在使用上的限制
C++这样的限定编程语言都提供了大量可以取代宏的方案:
1. const可以用于定义常量;
2. inline可以用于定义可被编译为内嵌代码的函数;
3. template可以用于以类型安全的方式定义各种标准操作,如min,max等;
4. enum可以用于定义枚举类型;
5. typedef可以用于定义简单的类型替换。
注意:宏对于支持条件编译非常有用,但对于细心的程序员来说,除非万不得已,否则是不会用宏来代替子程序的。
内联子程序
1. 由于inline函数暴露细节和增加代码量等因素,需要节制使用inline子程序;
注意:为性能原因而使用inline子程序的底线是:剖测代码并衡量性能上的改进。如果预期获得的性能收益不能说明为“剖测代码以验证性能改进”操心是值得的,那也就没有必要再牺牲代码质量而使用inline子程序了。
文章评论(0条评论)
登录后参与讨论