使用可搜索的名称
单字母名称和数字常量有个问题,就是很难再一大片文字中找出来
招MAX_CLASS_PER_STUDENT很容易,但是想找出数字7就麻烦了,他肯呢个是某些文件名或者是其他常量定义的一部分,出现在因为不同意图而采用的各种表达式中。如果改常量是个长数字,又被人错改过,就会逃过搜索,从而造成错误。
同样,e也不是一个便于搜索的号变量名。它是英文中最常用的字母,在每个程序、每段代码中都有可能出现。由此可见,长名称剩余短名称,搜得到的名称胜于用自造编码代写出的名称。
名称长短应与其作用于大小相对应。若变量或常量可能在代码中多处使用,则应赋予其便于搜索的名称。
比较下面的代码:
for (int j = 0; j < 34; j ++) {
s += (t[j] * 4) / 5
}
和
int realDaysPerIdealDay = 4; //实际天数 / 理想天数
const int WORK_DAYS_PER_WEEK= 5; // 每周工作日
const int NUMBER_OF_TASKS = 34;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++;) { //任务数量
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
类名
类名和对象名应该是名词或者名词短语,入Customer、WikiPage、Account和AddressParser。避免使用Manager、Processor、Data或Info这样的类名。类名不应当是动词。
方法名
方法名应当是动词或动词短语,如postPayment、deletePage或save。属性访问器、修改器和断言应该根据其值命名,并根据标准加上set、set和is前缀。
string name = employee.getName();
customer.setName('mike');
if (paycheck.isPosted() ...
重载构造器时,使用描述了参数的静态工厂方法名。例如,
Complex fulcrumPoint = Complex.FromRealNumber(23.0)
通常好于
Complex fulcrumPoint = new Complex(23.0);
可以考虑将相应的构造器设置为private,强制使用这种命名手段。
每个概念对应一个词
给每个抽象概念选一个词,并且一以贯之。
添加有意义的语境
比如addrFirstName、addrCity、addrStreet
比起firstName、city、street更能理解语境,更好的做法是写一个Address类
短小
代码应该短小更短小
1、代码块和缩进
if语句、else语句、while语句等,其中的代码块应该只有一行。该行打的应该是一个函数调用语句。这样不但能保持函数短小,而且,因为块内调用的函数拥有比较具有说明性的,名称,从而增加了文档的价值。
这个意味着函数不应该大到足以容纳嵌套结构。所以函数的缩进层级不应该多余一层或两层。
只做一件事情
函数应该做一件事情。做好这件事。只做这一件事。
判断函数是否布置做了一件事,还有一个方法,就是看是否能再拆出一个函数,该函数不仅是单纯地重新诠释其实现。
每个函数一个抽象层级
要确保函数制作一件事,函数中的语句都要在同一抽象层级上。
标识参数
向函数传入布尔值兼职就是骇人听闻的做法。这样做就是大声地宣布函数不止做一件事。如果标识为true将会这样做,标识为false则会那样做。方法调用render(true)对于可怜的读者来说仍然摸不清头脑。看到render(Boolean isSuite),少许有点帮助,不过仍然不够。应该把函数一分为二:renderForSuit()和renderForSingleTest()
参数对象
如果函数看来需要两个、三个或三个已上的参数,就说明一些参数应该封装为类了。如:
Cricle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
参数列表
有可变参数的函数可能是一元、二元甚至三元。超苹果这个数量就可能要犯错了
无副作用
比如checkPassword可能会有时序性耦合的问题,当我们调用完这个方法之后清空了会话,一些同事在使用的时候可能把它当做一个校验密码的工具方法,所以一些具有时序性的方法,我们需要在方法名中就写清楚
输出参数
比起appendFooter(s),report.appendFooter()要好得多
普遍而言,应避免使用输出参数,如果函数必须要修改某种状态,就修改所属对象的状态吧
分隔指令与询问
函数要么做什么事,要么回答什么事,二者不可得兼。比如在setName函数里就不要返回name
别重复自己
消除重复
如何写出这样的函数
一开始写的时候都很冗长而复杂。有太多牌的缩进和嵌套循环,有过长的参数列表。名称是随意取的,也会有重复的代码。不过配上一套单元测试,覆盖每行丑陋的代码会限制住自己。
然后要打磨这些代码,分解函数、修改名称、消除重复。缩短和重新安置方法,有时候还拆散类,同时保证测试通过。最后遵循以上列出的规则,组装好这些函数。
我并不从一开始就按照规则写函数。我想没人做得到。