本章要点
- 规模确定
- 函数层级
- 函数名
- 函数参数
- 不要有歧义
- 区分指令与询问
- 错误处理
- 消除重复
一、函数的规模
函数的第一规则是:短小
例如,在博客里面看到的一个很优秀的函数,我们无需了解他的逻辑,但是很清楚他要做的事。
//代码段3.1
int max(int a, intb) {
return a > b?a:b;
}
二、只做一件事
这里需要解释一下,什么一件事概念:如果函数包括了处于多个不同抽象层级上的多个步骤,那么我们认为他做了不止一件事。
如下面3.2中 实际做了3件事,A判断是否是测试页面;B如果是则容纳进设置和拆分步骤;C渲染成html;所以,在这里我们完全可以吧;A和B再拆分成函数,用有意义的名字包装起来;
//代码段3.2
public static String renderPageWithSetupsAndTeardowns(PageDatapageData, boolean isSuite)throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
return pageData.getHtml();
}
}
三、每一个函数一个抽象层级
如下面3.3中,初始化所有通道这个for循环就和上面的方法不在同一抽象层次上,应该将其抽象成另一个方法,在方法里,只完成“初始化所有通道”的工作。
//代码段3.3
Void init() {
configInit();
socketInit();
dbInit();
int i = 0;
for (i = 0;I < max_chn_num;i++){//初始化所有通道
G_user_chn[i].status = status_init;
//......
}
}
四、使用描述性名称,准确并保持一致的命名方式
五、参数的个数
六、函数不应带来副作用
- 该原则是对——只做一件事的扩展
意思是如果函数名称(注释)已经说明他做的事,那么就不要去做一些其他的事,比如在检查完用户名密码后,再去初始化会话。后者表名该函数只能在特定的时候调用,时机不对,可能会导致恶劣的结果。
七、分隔指令与询问
- 函数要么做什么事,要么执行什么事,但两者不可得兼。并且需要在语义上给予准确的说明,不可模糊。体会以下第二段和第三段代码的含义。
//代码段3.4
public boolean set(String attribute,String value)
if(set("username","unclebb")).....
if(attributeExists("username")){
set("username","unclebb");
}
八、使用异常类而非返回错误码
-
8.1 使用异常类可以使错误代码处理从主路经代码里抽离出来
这个逻辑在第七章有详述,这里不再叙述 - 8.2 将try-catch里的逻辑代码抽离出来,形成有意义的函数
- 8.3 错误代码使得所有类都对其产生依赖,使用异常则新的异常可以从异常类派生而来,无需重新编译和部署(这个不是很懂)
九、不要重复自己
在函数中重复一段代码,将会导致一旦逻辑改变,你将会改动多个地方,带来臃肿、不一致和可能产生的错误。
重复可能是软件中一切邪恶的根源。许多原则与实践规则都是为控制与消除重复而创建