考虑下面的两个代码段。 哪一个更好,为什么?如果你 有任何其他想法,请做 提到。我在哪里可以找到答案 像这样的编码实践?如果你 知道任何书/文章, 请分享。
//代码1
bool MyApplication::ReportGenerator::GenerateReport(){
bool retval = false;
do{
if (!isAdmin()){
break;
}
if (!isConditionOne()){
break;
}
if (!isConditionTwo()){
break;
}
if (!isConditionThree()){
break;
}
retval = generateReport();
} while(0);
return retval;
}
//代码2
bool MyApplication::ReportGenerator::GenerateReport(){
if (!isAdmin() || !isConditionOne() || !isConditionTwo() || !isConditionThree()){
return false;
}
return generateReport();
}
罗伯特C.马丁的干净代码是一本很好的书来处理这个问题。但是,我想这本书倾向于Java。
更新
我故意使用do {} while(0);因为我不想使用goto循环。
我想摆脱这么多if和break语句,所以我提出了Code 2.
我在回复中看到的是Code1和Code2的一组混合响应。与Code 1(我认为更好)相比,有些人更喜欢goto。
答案 0 :(得分:40)
我真的不喜欢以这种方式使用do / while循环。另一种方法是将Code2中的条件分解为单独的if检查。这些有时被称为“保护条款”。
bool MyApplication::ReportGenerator::GenerateReport()
{
if (!isAdmin())
return false;
if (!isConditionOne())
return false;
// etc.
return generateReport();
}
答案 1 :(得分:25)
我个人更喜欢第二个代码段的变体。短路将起作用,但条件不那么冗长。
bool MyApplication::ReportGenerator::GenerateReport()
{
if(isAdmin() && isConditionOne() && isConditionTwo() && isConditionThree())
{
return generateReport();
}
return false;
}
它说一切都在一个干净的地方。 “如果满足所有这些条件,那么就这样做。否则,不要这样做。”
我觉得你的第一个代码段通过将条件分布在12行中使得逻辑变得更难看。此外,封装循环可能会导致某人进行双重拍摄。
答案 2 :(得分:17)
bool MyApplication::ReportGenerator::GenerateReport()
{
return isAdmin()
&& isConditionOne()
&& isConditionTwo()
&& isConditionThree()
&& generateReport(); // Everything's ok.
}
答案 3 :(得分:8)
bool MyApplication::ReportGenerator::GenerateReport(){
if ( ! isAdmin () ) return false ;
if ( ! isConditionOne () ) return false ;
if ( ! isConditionTwo () ) return false ;
if ( ! isConditionThree() ) return false ;
return generateReport() ;
}
答案 4 :(得分:6)
这实际上取决于代码的未来期望。上面的Code1暗示可能为每个条件添加额外的逻辑;上面的代码2意味着有一个合理的条件分组。如果您希望以后为条件添加逻辑,则Code1可能更相关;但是,如果你不这样做,Code2可能因为简洁和隐含的分组而更加明智。
答案 5 :(得分:5)
我更喜欢修改样本2:
bool MyApplication::ReportGenerator::GenerateReport()
{
bool returnValue = false;
if (isAdmin() &&
isConditionOne() &&
isConditionTwo() &&
isConditionThree())
{
returnValue = generateReport();
}
return returnValue;
}
它具有为该功能提供单个出口点的好处,建议使用该出口点以便于维护。我发现垂直堆叠条件而不是水平更容易快速读取,如果需要,可以更容易地评论各个条件。
答案 6 :(得分:4)
代码1,IMO,最糟糕的是因为它不会立即传达仅在某些情况下生成代理的意图含义。
使用:
if (condition_1) return false;
if (condition_2) return false;
...
会更好。
另外,我在代码1中不喜欢的是它尝试使用while和break(其中 gotos)来屏蔽gotos。我宁愿直接使用goto,至少可以更容易看到着陆点的位置。
代码2的格式可能看起来不错,我想:
bool MyApplication::ReportGenerator::GenerateReport(){
if (!isAdmin() || !isConditionOne() ||
!isConditionTwo() || !isConditionThree()) {
return false;
}
return generateReport();
}
或类似的东西。
答案 7 :(得分:4)
我喜欢作为版本2的变体的答案,但只是为了提供替代方案:如果这些条件在逻辑上捆绑在一起,则可能需要在其他地方再次检查它们。如果这是真的,那么辅助函数可能会更好地完成工作。像这样:
bool isReportable(anyParametersNeeded){
//stuffYouWantToCheck
}
bool MyApplication::ReportGenerator::GenerateReport(){
if (isReportable(anyParametersNeeded)){
return generateReport();
}
return false;
}
由于此函数很小,您甚至可以内联它(或让编译器决定;))。另一个好处是,如果你想在将来加入一些额外的支票,你只需改变那个功能,而不是每个地方都改变它。
答案 8 :(得分:4)
您认为最好的表达了代码试图说的内容。你需要哪一个最难理解的工作?
我会这样做:
bool MyApplication::ReportGenerator::GenerateReport(){
if (isAdmin() && isConditionOne() && isConditionTwo() && isConditionThree()){
return generateReport();
} else {
return false;
}
}
因为:
A)。喜欢说出我想要的东西而不是我不想要的东西 B)。喜欢对称,if和else。显然所有案例都包括在内。
答案 9 :(得分:3)
关于例1:如果你想要转到,你为什么不写goto ???它比你的建议更清晰。考虑到goto应该很少使用,我投票给#2。
答案 10 :(得分:2)
我的习惯是以这种方式避免if-blocks:
bool MyApplication::ReportGenerator::GenerateReport(){
bool report = !( isAdmin() || isConditionOne() ||
isConditionTwo() || isConditionThree() );
return report ? generateReport() : false;
}
答案 11 :(得分:1)
我个人更喜欢样本2.它将那些不会导致报告生成的项目分组。
就通用编码指南而言,代码完成(Amazon))是编码风格问题的一个很好的参考。
答案 12 :(得分:0)
我认为开关可以更好地解决您的问题。您需要重载该方法以获取int参数,我不知道您是否想要这样做。
Bool MyApplication::ReportGenerator::GenerateReport(int i)
{
switch(i)
{
case 1:
// do something
break;
case 2:
// do something
break;
// etc
}
return GeneratReport()
}
不确定你的计划是什么,因为你以递归方式调用该方法,并且有时你会想要离开该方法。
答案 13 :(得分:0)
答案 14 :(得分:0)
代码完成是一本通常推荐的书,它详细介绍了这些风格问题。另外,请考虑查看一些已发布的组织风格指南,看看他们是否对此问题有任何意见;例如Google's Style Guide。
至于我喜欢什么,第二个例子在我看来要好得多。第一个基本上是滥用do {} while结构,以避免使用goto,教条地坚持“不惜一切代价避免冒险”的字母,同时缺少“代码清晰,不使用非显而易见的语言技巧”的精神。
事实上,甚至根本不使用goto的唯一理由就是教条上坚持使用“每个函数只有一个返回语句”的方法,当你可以使用简单易读的
时if (!isAdmin()){
return false;
}
else if (!isConditionOne()){
return false; }
else if (!isConditionTwo()){
return false; }
else if (!isConditionThree()){
return false; }
else
return generateReport();
其他想法?
不要命名用于保存计算成功状态“returnValue”或类似的局部变量。 显然无论你返回的是返回值,任何能读C的人都可以看到返回的内容。告诉我它拥有什么计算。名称“returnValue”没有提供关于它是真还是假的含义的信息。在这个例子中,“canGenerateReports”或类似内容将更为可取。
答案 15 :(得分:0)
我个人更喜欢将for
,while
和do ... while
循环作为实际循环。在第一个代码示例中,情况并非如此。因此,我会选择示例2.或者,正如其他人已经说过的那样,将示例2分解为多个if ... return
语句。
答案 16 :(得分:-2)
我在不同的情况下使用了类似的东西,但你的第一个IMO过于复杂:
bool MyApplication::ReportGenerator::GenerateReport(){
bool retval = false;
if (!isAdmin()){
}
else if (!isConditionOne()){
}
else if (!isConditionTwo()){
}
else if (!isConditionThree()){
}
else
retval = generateReport();
return retval;
}