译:Derry Zhang/2006-03-17
注:其实这本书市面上已经有中译本了,之所以自己再次翻译,一来是本有计划精读该书,二来又有提高英语阅读水平的需要和想法,所以就不怕浪费时间和精力来做这件事情。如果您看到其中有任何错误请及时告知我,不胜感谢!
命名规范(Names)
1.1 起合适的名字(Make Names Fit)
名称是编程的心脏。过去人们笃信只要知晓了某人的真实名字就可以从那个人身上获得魔力。如果你可以为一件东西想出一个真实名称,那么你就给了你自己和后来者以这些字码的魔力。先别笑!名字其实是关于某件事物的生态环境进程的长期深入思考的结果。只有那些对整个系统真正了解的程序员才能够创造出“适合”这个系统的名称。如果名称合适,那么就需要任何事情都很自然的柔和在一起,关系明确,含义可追溯,并且可以为普通人所期待和推理。
如果你发现你的名称到处都是"Thing"或者"Doit"之类,那么你大概就需要取重新审视你的设计了。
类名
你应该彻底理解类的真实含义之后再去命名它。如果你无法思考得出它究竟是什么,那么这就意味着你还没有对这个设计有着足够的认识。超过三个单词的混和名称意味着你的设计有可能混淆了系统中的各个实体。这是你需要重审你的设计。试试一张CRC卡片讨论来验证一下你的对象是否承担了它们本不该承担的责任。避免在派生类中沿用其父类的名称,每个类都应该有自己独立的类名,这与它究竟继承自哪个父类无关。
后缀有时候是很有效的。例如,如果你的系统中用到了代理(agent),那么就可以用诸如DownloadAgent来表示其真实信息。
方法和函数命名
通常来讲,每个方法和函数都是执行一段行为,因而其名称也应能够清楚的说明其究竟是做什么的:CheckForErrors()就比ErrorCheck()要好,DumpDataToFile()比DataFile()更合适。同时这也可以使函数或者数据对象更加容易区分。类名一般都是名词。通过在函数名称中使用动词,并且遵循其他的命名规则,那么你的代码可读性可以大大提高(读起来更加自然)。
后缀有时候也很有效:
Max - 表示一个变量可以取得的最小值
Cnt - 计数器变量的当前值
Key - 键值
例如:RetryMax表示“重试”的最大次数,RetryCnt表示当前重试了多少次
有时候前缀也是很有用的:
Is - 用来提出问题,一旦你发现了Is则表示提出了一个问题
Get - 获取值
Set - 设置值
例如:IsHitRetryLimit.
1.2在名称中包含单位
如果变量表示时间、重量或者其他单位的含义,那么要把单位加到变量名中来。这样开发人员就可以更方面的辨认。例如:
uint32 mTimeoutMsecs;
uint32 mMyWeightLbs;
将变量转变成类将是个更好的做法,这样非法的转化就可以被捕获到。
1.3勿用全部大写字符的缩写词
- 设想一下你在使用缩略词的时候,无论在什么时候都会选择使用全部的大写字母,而不是首字母大写,而后面的字符都小写呢?
解释
- 在使用缩略词的时候人们的直觉是非常不同的。最好的选择就是统一思想,这样变量名才能够是完全可预测的。
- 例如NetworkABCKey.请注意,ABC中的C和key中的K如何去分辨呢?有些人并不在意这些,然而其他人就非常厌恶。故而你在不同的代码中可能会发现好几种规则,你永远不知道该叫这个变量什么名字。
实例
class FluidOz // 而非FluidOZ
class NetworkAbcKey // 而不是NetworkABCKey
1.4类的命名
- 使用大写字母来作为单词的分割方式,其他字符一律小写
- 类名的第一个字符要大写
- 别使用下划线('_')
解释
- 在众多的命名策略中,很多人都发现本方法是最好的折中。
class NameOneTwo
class Name
1.5类库命名
- 由于名字空间(name spaces)越来越被广泛的实现,在使用名字空间的时候应当避免与其他开发商或者组织的类库名称冲突的问题。
- 在使用名字空间的时候,一种通用的避免类名冲突的做法就是在类名之前加上一个唯一的字符串标识。两个字符就足够了,当然再稍微多几个字符也没有关系。
示例
John Johnson的完整数据结构库就可以使用JJ作为前缀,故而类命名可以如下所示:
class JjLinkList
{
}
1.6类方法命名
- 命名法则同类的命名方式
解释
- 在众多不同的命名策略中,很多人都发现本方法是最好的折中。
示例
class NameOneTwo { public: int DoIt(); void HandleError(); }
1.7类属性命名
- 属性名称前面应该加上字符"m"。
- 在"m"后面使用和类命名相同的规则。
- "m"是最优先靠前的名称修饰符,例如比指针修饰符"p"还应靠前。
解释
- 在属性前面加上个"m"就避免了和方法名称之间的混淆。因为你的方法和属性常常看起来极为相似,尤其对那些存取程序来说更是如此。
示例
class NameOneTwo
{
public:
int VarAbc();
int ErrorNumber();
private:
int mVarAbc;
int mErrorNumber;
String* mpName;
}
1.8方法的参数命名
- 首字符应当小写
- 就像类命名规则一样,后续的所有单词首字符都应大写
解释
- 你可以声明哪些参数是通过变量传递的
- 同时你也可以没有歧义的使用和类名相同的名称
示例
class NameOneTwo { public: int StartYourEngines( Engine& rSomeEngine, Engine& rAnotherEngine); }
1.9堆栈变量命名
- 全部使用小写字符
- 使用下划线'_'作为单词分隔符
解释
- 通过这种方式,变量的作用域在代码中就显得很明显
- 现在看上去,代码中的所有变量都可以明显的确认出来
示例
int NameOneTwo::HandleError(int errorNumber) { int error= OsErr(); Time time_of_error; ErrorProcessor error_processor; Time* p_out_of_time= 0; }
虽然看上去标准的指针符号并不怎么令人满意,但它至少保证了一致性。
那么,你如何处理静态变量呢?因为没有理由在函数体内声明本地静态变量,故而没必要再为此而发明一种新的语法。