上一篇关于函数的文章写到编写函数的几个注意事项:
函数要短小。
函数只应该做一件事。
函数的参数要尽量少,避免使用输出函数。
函数要无副作用。
函数要区分指令和询问。
本篇接着写关于函数的其他知识。
避免传标识符参数给函数。标识符是指true或false。标识符参数意味着函数至少要做两件事情:true,做一件事;false,做另一件事。我的代码、其他同事的代码,用标识符做参数的函数,很常见。如果要将标识从函数中消除,那么将增加函数个数,而且,在函数中由标识符带来的if...else...结构将转移到函数之外。这似乎没有好处。
指令型函数要使用异常处理代替状态码返回。请看代码A。
if(deleteUserById(id) === ERROR_CODE){
if(deleteUserFriendById(id) === ERROR_CODE){
return true;
}else{
log(errorMsg);
}
}else{
log(errorMsg);
}
deleteUserById(id)、deleteUserFriendById(id)都是指令型函数。将上面的代码改造为代码B。
try{
deleteUserById(id);
deleteUserFriendById(id);
}catch(Exception e){
log(e);
}
代码B明显简洁了很多,但是我不明白:不同函数抛出的异常是不同的,捕捉到异常后进行处理的代码也可能是不同的。假如需要针对不同的代码,进行不同的处理,必须去了解封装在函数内部的代码才行。这违背了“开放—封闭”原则。工作至今,我只用过几次此类处理错误的方式。需要深入函数内部去了解所抛出的异常情况,是我不使用此方式的原因。但这个方式是专家提倡的,我需慢慢琢磨,直至透彻理解它的精妙。
代码B可以进一步改写为代码C。
try{
deleteUserAndFriendById(id);
}catch(Exception e){
log(e);
}
function deleteUserAndFriendById(id){
deleteUserById(id);
deleteUserFriendById(id);
}
从代码B到代码C,遵循着编写函数的又一个原则:把其他大段代码丑陋不堪的try...catch中剥离出来。至于为什么这么做,除了简洁,我想不出其他原因。
函数命名,应该使用动词或动词短语+名词的形式。例如,write(name),就是很好的函数名称。
说点题外话。今日周五,懈怠了,中午一直在看动漫,没有写作。
同事前些天推荐使用markdown写作,今天尝试了一下。我虽然没有掌握所有的markdown技巧,但稍加运用,就有不少好处:排版好看了些,尤其是代码的排版。