如何调用这种编写代码的方式?

时间:2009-09-10 13:09:26

标签: c++ language-agnostic

我正在审查一个相当古老的项目并且已经第二次看到这样的代码(C ++ - 就像伪代码一样):

if( conditionA && conditionB ) {
   actionA();
   actionB();
} else {
   if( conditionA ) {
      actionA();
   }
   if( conditionB ) {
      actionB();
   }
}
此代码中的

conditionA计算两个计算的结果相同,conditionB的结果相同。所以代码只相当于:

if( conditionA ) {
   actionA();
}
if( conditionB ) {
   actionB();
}

所以前一种变体只是两次代码相同的效果。如何调用编写代码的方式(我的意思是前一种变体)?

12 个答案:

答案 0 :(得分:13)

这确实是错误的编码实践,但要注意,如果条件A和B评估有任何副作用(var增量等),则两个片段不相等。

答案 1 :(得分:6)

我称之为糟糕的代码。虽然我倾向于在项目中找到类似的结构,但没有进行任何代码审查。 (或其他松散的开发实践)。

答案 2 :(得分:4)

专家?看看这部分:( conditionA && conditionB) 基本上,如果conditionA碰巧是假的,那么它就不会评估conditionB。

现在,这将是一个糟糕的编码风格,但如果conditionA和conditionB不只是评估数据,但如果这些条件背后还有一些代码可以改变数据,那么两种符号之间可能存在巨大差异!

如果conditionA为false,则conditionA被评估两次,conditionB仅被评估一次。 如果conditionA为true且conditionB为false,则两个条件都会被计算两次。 如果两个条件都为真,则两者都只执行一次。

在第二个建议中,两个条件只执行一次......因此,如果两个方法都评估为真,这些方法只是等效的。

为了使事情变得更复杂,如果conditionB为false,那么actionA可以更改会改变此验证的内容!因此,else分支也将执行actionB。但如果两个条件的计算结果为true且actionA会将conditionB的计算结果更改为false,那么它仍会执行actionB。

我倾向于将这种代码称为:“为什么当你可以用艰难的方式做事时让事情变得容易?”并认为这是一种设计模式。实际上,它是“Mortgage-Driven development”,其中代码变得更加复杂,因此主要开发人员将是唯一理解它的人,而其他开发人员将变得困惑并希望放弃重新设计整个事情。因此,原始开发人员只需要维护这段代码,这就是所谓的“工作安全”,因此可以支付多年的抵押贷款。


我想知道为什么像这样会被使用,然后意识到我在自己的代码中使用了类似的结构。相似但不一样:

if (A&&B){
  action1;
} elseif(A){
  action2;
} elseif(B){
  action3;
} else{action4}

在这种情况下,每个操作都会显示不同的消息。仅通过连接两个字符串无法生成的消息。比如,它是游戏的一部分,A检查你是否有足够的能量,而B检查你是否有足够的质量。你没有足够的质量和能量,你不能再建造任何东西,需要显示一个严重的警告。如果你只有能量,那么你需要发现更多质量的警告就足够了。只有能量,你的建设者需要充电。两者都可以继续构建。四种不同的动作,因此这种奇怪的结构。 然而,Q中的样本显示出完全不同的东西。基本上,你会收到一条消息,说你已经超出质量,而另一条消息则是你精力充沛。这两条消息不会合并为一条消息。

现在,在这个例子中,如果conditionA会检测能量水平而conditionB会检测到质量水平,那么两种解决方案都可以正常工作。现在,如果actionA告诉你的建造者减少他们的质量并开始充电,你会在游戏中突然再次获得一点质量。但是如果条件B表明你已经用完了,那就不再那么真了!仅仅因为actionA再次释放了质量。如果actionB是命令告诉建筑者一旦他们能够开始收集质量,那么第一个解决方案将给所有建造者这个命令,他们将首先开始收集质量,然后他们将继续他们的其他行动。在第二种解决方案中,不会给出这样的命令。施工人员再次充电,并开始使用刚刚释放的小质量。如果每5分钟进行一次检查,那么那些建造者就会例如在一分钟内充电,闲置4分钟,因为它们已经用完了。在第一个解决方案中,他们会立即开始收集质量。

是的,这是一个愚蠢的例子。再次扮演最高指挥官。 :-)只是想提出一个可能的方案,但它可以改进很多!...

答案 3 :(得分:3)

这是由不知道如何使用Karnaugh Map的人编写的代码。

答案 4 :(得分:3)

这非常接近'fizzbuzz'设计模式:

if( fizz && buzz ) {
   printFizz();
   printBuzz();
} else {
   if( fizz ) {
      printFizz();
   }
   else if( buzz ) {
      printBuzz();
   }
   else {
      printValue();
   }
}

也许代码起初是fizzbuzz的一个实例(也许是复制粘贴的),然后由于要求略有不同而稍微重构到你今天所看到的内容,但是重构并没有达到应有的程度。有(布尔逻辑有时可能比人们想象的要复杂一点 - 因此fizzbuzz作为采访清除技术)。

答案 5 :(得分:2)

我也称它为坏代码。

没有最好的缩进方式,但有一条黄金法则:选择一个并坚持下去。

答案 6 :(得分:2)

这是“冗余”代码,是的,它很糟糕。如果必须在对actionA的调用中添加一些前置条件(假设前置条件不能放入actionA本身),我们现在必须在2个位置修改代码,因此冒着忽略其中一个的风险。

在这些时候,您可以更好地删除一些代码,而不是编写新代码。

答案 7 :(得分:2)

效率低下的代码?
此外,可以称为 每行付费

答案 8 :(得分:1)

我会称之为'两次更好'。它是这样的,以确保运行时真正理解问题;)。

(虽然在多线程,不安全的环境中,两种变体之间的结果可能不同。)

答案 9 :(得分:1)

我可以称之为“我上个月写的代码,当时我很匆忙/没有专心/累”。它发生了,我们都犯了这样的错误。只需改变它。如果你想,你可以尝试找出是谁做的,希望不是你,并给他/她反馈。

答案 10 :(得分:1)

既然你说你已经不止一次看过这个,那么由于累了,这似乎不仅仅是一次性错误。我看到有人反复提出这样的代码有几个原因:

  1. 代码最初是不同的,经过重构,但无论谁做到这一点都认为这是多余的。
  2. 无论谁做到这一点都没有很好地掌握布尔逻辑。
  3. (另外,这可能会比你的简化剪辑显示更多的可能性。)

答案 11 :(得分:1)

正如pgast在评论中所说,如果actionA影响conditionB,这个代码没有任何问题(请注意,这不是具有副作用的条件,而是具有副作用的行为(您可以期待)