编程规范:判断语句,不要一下子判断多个条件
例如:
(1)
if( userName!=null && userName.length()>0 && userType!=null && userType.length()>0 && userEmail!=null && userEmail.length()>0){
//....
}else{
//....
}
当然,抽出一个isEmpty的字符串判断函数,也可以简写成:
(2)
if( (!isEmpty(userName)) && (!isEmpty(userType)) && (!isEmpty(userEmail))){
//....
return true;//判断条件通过
}else{
//....
return false;
}
这样写有什么问题?(1)的问题其实就是看起来太长了,不容易理解,那么(2)呢?
以我个人看来,(2)的逻辑表达还是很清晰的,但是问题在于没有满足业务需求。
一般做一个接口,可能会这样写需求定义:
检查参数
如果参数正确,完成XXXXX业务;
如果参数不正确,返回失败。
显性需求就是这几条了,那么隐形需求呢?有一些隐形需求,是一些约定俗成的东西,一定也要铭记在心的。比如,例子中的接口,是否有这样一个需求:
如果参数不正确,请告诉调用者是哪个不正确,为什么不正确
从这条隐形需求来看上面的例子,可以看到,(2)最大的问题是,else里面怎么写?如果不是开发商业软件的人,或者不注意团队合作开发的人,也许会说“没什么问题,if后边正常业务流程,else返回条件检查错误”,但是,前边的if里既然这么是几个条件一起判断的,那后面的else里你还怎么返回?
直接返回一个false当然是正确的返回,但是,如果调用者发现返回的是一个false,那么,怎么确定到底是哪个变量,userName、userType、userEmail里边的哪一个是空,还是null?难道你在else里边还要再判断一回吗?
当然,你也可以假设这些变量传递到你写的这个方法之前,先在日志(甚至控制台也罢了)输出了,这当然在你的方法返回错误时,能够查找问题所在,问题是你这个假设是否能成立呢?恐怕不一定吧。
再者,对这个简单的例子,在外边输出这几个变量就行了,但是,如果这个函数里的判断比较复杂呢,参数需要经过复杂的转换再判断呢?那种情况下,从入口参数的原始值不一定能看出问题只所在。
再有,如果你不是把代码集成给调用者,而是提供一个jar包(或者,如果是C写的代码,给的是一个DLL的情况)给调用者使用呢?是否调用者只能把问题报告给你再判断呢?
如果不能从返回值里看到返回false具体的原因,那么,如果发现这个函数的调用者到这里出错了,即便把问题报告给你,也只能使用同样的参数和条件,在IDE里调试了。
所以,在这些非常简单的场景下,也应该考虑问题尽量周全,最简单的方法就是:
if( isEmpty(userName)){
//....
return USERNAME_IS_EMPTY;
}
if( isEmpty(userType)){
//....
return USERTYPE_IS_EMPTY;
}
if( isEmpty(userEmail)){
//....
return USEREMAIL_IS_EMPTY;
}
这样,外边的人想怎么用,都由他的业务场景决定。
或者:
if( (!isEmpty(userName)) && (!isEmpty(userType)) && (!isEmpty(userEmail))){
//....
return true;//判断条件通过
}else{
throw new ArgumentInvalid(".....");
}
这个程序段,你可以通过异常,告诉调用者,什么样的参数才能检查通过,而他送的参数都是什么。虽然异常的代价要比判断高一些,但这个也比(1)和(2)好一些。
其实说了这么多,也是表明这种细节,是编码的基本规则的延伸,
(一)
要清晰表达业务需求(隐性需求:能够给出到底是哪个参数不对,为什么不对)
(二)
不要随便假设条件(假设别人也可以调试你的代码)
这样来写,的确很繁琐,但是写程序是为了干什么?要
完成需求,如果不能完成需求,代码多简洁,又有什么价值呢?
很多人都那么喜欢在一条if语句里判断很多条件,的确能减少好几行代码,可是,
只要代码清晰易懂,多写几行代码又有什么不可以呢?
有时候,就得用最基本的方法来表达业务逻辑,这需要有脚踏实地的态度,平和的心态。一想省事,往往到最后就会发现路走错了。再者,就是编程者老老实实的态度,平凡朴实的编码。