关键思想
把你超长的表达式,拆分成更容易理解的小模块;使其不成为读者阅读上的“减速带”
1 “解释型”变量
拆分表达式最简单的方法是引入一个额外的变量,让它来表达一个小一点的子表达式。
这个额外变量有时候被称作“解释”变量,因为它可以帮助解释子表达式的含义。
来个判断用户名称的例子
BAD
string userInput = "kimmy:1989/4/11:male"; if (userInput.Split(':').FirstOrDefault().Trim() == "kimmy") { Console.WriteLine("是kimmy"); }
GOOD 引入“解释”变量
string userInput = "kimmy:1989/4/11:male"; string userName = userInput.Split(':').FirstOrDefault().Trim(); if (userName == "kimmy") { Console.WriteLine("是kimmy"); }
此处,我们使用userName,来解释该行对userInput进行一系列操作的目的。
在if判断的时候,我们清晰的明白:判断的对象,是用户输入的用户名。
2 “总结型”变量
你可以一眼看出作用的代码块,不需要引入额外的“解释型”变量,但是把它装入一个“总结型”变量仍然有用。
使用“总结型”变量的目的是:用一个短很多的名字来代替一大块代码 来更加直接地向读者传递编码意图。
来个权限判断的例子
BAD
int userRights = 7; int editRights = 1; //如果用户有编辑的权限 if ((userRights & editRights) == editRights) { } //如果用户没有编辑权限,文档是只读的 if ((userRights & editRights) != editRights) { }
GOOD 引入“总结型”变量
int userRights = 7; int editRights = 1; bool isUserHasEditRights = (userRights & editRights) == editRights; //如果用户有编辑的权限 if (isUserHasEditRights) { } //如果用户没有编辑权限,文档是只读的 if (isUserHasEditRights==false) { }
3 善用“摩根定理” 简化逻辑判断
如果你学过“电路”或者“逻辑课”,就记得有个叫“摩根定理”,把它应用于布尔表达式,可以得出两个等价的写法。
- not (a or b or c) <=> (not a) and (not b) and (not c)
- not (a and b and c) <=> (not a) or (not b) or (not c)
如果记不住这个写法,一个口诀就是(分别取反,转换与或)
比如判断文件是否可以操作
BAD 最外层还有反转,易读性差
if ((isFileExist && !isFileProtected)==false) //文件无法写入
GOOD 简化了外层反转的逻辑
现在我们就用"摩根定理",去掉外面的逻辑反转; 谨记口诀(分别取反,转换与或)
是不是看起来代码的逻辑简单多了:如果文件不存在,或者文件存在保护,则无法写入。
if (!isFileExist || isFileProtected) //文件无法写入
4:警惕被滥用的短路逻辑
在javascript里,短路逻辑用来初始化参数很方便,比如
function showUserName(userName) { //如果没指定用户名称,则默认使用游客 userName = userName || "游客"; alert(userName); }
使用短路逻辑很方便,但是有时可能被滥用,以实现复杂逻辑
比如 我们要检查是否找到了桶
assert(!(bucket = FindBucket())
现在需求变更了,还要检查桶有没有被占用,另外接手的程序员见缝插针,写了个短路逻辑进去
assert((!(bucket = FindBucket())) || !bucket.isOccupied());
尽管它只用一行代码就实现了两个检查的点,但是付出的代价是,我们在阅读的时候需要停下来想一想这个代码的意思--得不偿失。
改进的方法有很多,最简单的方法是分成两个语句:
//确保找到篮子 assert(!bucket = FindBucket()); //确保篮子没被占用 assert(!bucket.isOccupied());
5 拆分巨大的语句
还记得DRY原则吗?(don‘t repeat yourself)
把重复使用的变量提取成公用变量(不是全局变量,生命周期只局限在函数内。滥用全局变量会导致可读性变差)。
把重复使用的代码块提取成公用方法。
c/c++里面还可以使用“宏”来替你做重复的事情。