我和一位同事对以下哪项更优雅存在争议。我不会说谁是谁,所以它是公正的。哪个更优雅?
public function set hitZone(target:DisplayObject):void
{
if(_hitZone != target)
{
_hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
_hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
_hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);
_hitZone = target;
_hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
_hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
_hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);
}
}
...或...
public function set hitZone(target:DisplayObject):void
{
if(_hitZone == target)return;
_hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
_hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
_hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);
_hitZone = target;
_hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
_hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
_hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);
}
答案 0 :(得分:40)
在大多数情况下,早期返回会降低复杂性并使代码更具可读性。
这也是Spartan programming中应用的技术之一:
最少使用控制
- 使用专门的最小化条件的使用 构造这样的三元化, 继承,以及类等类 默认值,类一次和类 分离器
- 使用早期
return
简化条件。- 通过使用动作应用程序最大限度地减少循环结构的使用 Class Separate和Class等类 类FileSystemVisitor。
- 通过早期退出简化迭代逻辑(通过
醇>return
,continue
和break
语句。
在您的示例中,我会选择选项2,因为它使代码更具可读性。检查函数参数时,我使用相同的技术。
答案 1 :(得分:17)
这是可以违反规则(即最佳实践)的情况之一。通常,您希望函数中的返回点尽可能少。实际的原因是它简化了对代码的读取,因为您可以始终假设每个函数都将获取其参数,执行其逻辑并返回其结果。为各种情况提供额外的回报往往会使逻辑变得复杂,并增加了阅读和完全理解代码所需的时间。一旦你的代码到达维护阶段,那么多个返回会对新程序员的生产力产生巨大影响,因为他们试图破译逻辑(当评论稀疏且代码不清楚时,它尤其糟糕)。该问题相对于函数的长度呈指数增长。
那么为什么在这种情况下每个人都喜欢选项2?这是因为您正在设置一个函数,该函数通过验证传入数据或可能需要检查的其他不变量来强制执行。构造验证的最漂亮的语法是检查每个条件,如果条件失效,则立即返回。这样,您不必通过所有检查维护某种isValid布尔值。
总结一下:我们真正关注的是如何编写验证代码而不是一般逻辑;选项2更适合验证码。
答案 2 :(得分:11)
只要将早期返回组织为函数/方法体顶部的块,我认为它们比添加另一层嵌套更具可读性。
我尽量避免身体中间的早期回归。有时它们是最好的方式,但大多数时候我认为它们很复杂。
此外,作为一般规则,我尝试最小化嵌套控制结构。显然你可以把这个拿得太远,所以你必须谨慎使用。将嵌套if转换为单个switch / case对我来说更加清晰,即使谓词重复了一些子表达式(并且假设这不是一个语言中的性能关键循环,对于子表达式消除来说太愚蠢)。特别是我不喜欢长函数/方法体中嵌套ifs的组合,因为如果由于某种原因跳到代码的中间,你最终会向上和向下滚动以精神重建给定行的上下文。
答案 3 :(得分:4)
根据我的经验,在项目中使用早期返回的问题是,如果项目中的其他人不习惯他们,他们就不会寻找它们。如此早期的回报 - 如果涉及多个程序员,请确保每个人至少知道他们的存在。
我亲自编写代码以便尽快返回,因为延迟返回通常会引入额外的复杂性,例如尝试安全地退出一堆嵌套循环和条件。
因此,当我查看一个不熟悉的函数时,我要做的第一件事就是查找所有return
s。真正有用的是设置语法着色以使return
具有与其他任何颜色不同的颜色。 (我选择红色。)这样,return
成为确定函数功能的有用工具,而不是为不警情的人隐藏绊脚石。
答案 4 :(得分:1)
啊是监护人。
Imho,是的 - 它的逻辑更清晰,因为返回是明确的并且恰好在条件旁边,它可以很好地与类似的结构分组。当“return”被“throw new Exception”替换时,这更加适用。答案 5 :(得分:1)
如前所述,早期返回更具可读性,特别是如果函数体长,你可能会发现在3页函数中错误地删除了}(本身并不是很优雅)并且试图编译它可能需要几分钟的非自动化调试。
它还使代码更具说明性,因为这是你将它描述给另一个人的方式,所以开发人员可能非常接近理解它。
如果稍后函数的复杂性增加,并且你有很好的测试,你可以简单地将每个替代项包装在一个新函数中,并在case分支中调用它们,这样你就可以保留声明式样式。
答案 6 :(得分:0)
在这种情况下(一个测试,没有else子句)我喜欢测试和返回。它清楚地表明,在这种情况下,无需阅读函数的其余部分就无所事事。
然而,这是分裂最好的头发。我相信你必须担心更大的问题:)
答案 7 :(得分:0)
选项2更具可读性,但是当可能需要添加else时,代码的可管理性会失败。
所以,如果你确定,没有别的选择2,但如果可能有其他条件的范围,那么我更喜欢选项1
答案 8 :(得分:0)
选项1更好,因为您应该在程序中拥有最少数量的返回点。 有像
这样的例外if (a) { return x; } return y;
因为语言的工作方式,但总的来说,最好只有尽可能少的退出点。
答案 9 :(得分:0)
我更喜欢避免在函数开头立即返回,并且尽可能放置限定逻辑以防止在调用之前进入方法。当然,这取决于方法的目的。
但是,如果方法简短易读,我不介意在方法中间返回。如果方法很大,在我看来,它已经不是很易读,所以它将被重构为具有内联返回的多个函数,或者我将在结尾处通过单个返回显式地从控制结构中断。
答案 10 :(得分:0)
我很想把它关闭,因为我已经看到了一些类似的线程,包括Invert “if” statement to reduce nesting,它有很好的答案。
我现在就让它活着...... ^ _ ^
为了得到答案,我相信早期作为保护条款的回归比深度嵌套的if更好。
答案 11 :(得分:0)
我已经看过两种类型的代码,我更喜欢第一种代码,因为它看起来很容易阅读并且对我来说是可以理解的,但是我已经读过许多早期存在的地方是更好的方法。
答案 12 :(得分:0)
至少有另一种选择。将实际工作的细节与是否执行工作的决定分开。如下所示:
public function setHitZone(target:DisplayObject):void
{
if(_hitZone != target)
setHitZoneUnconditionally(target);
}
public function setHitZoneUnconditionally(target:DisplayObject):void
{
_hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
_hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
_hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);
_hitZone = target;
_hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
_hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
_hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);
}
这三个中的任何一个(你的两个加上上面的第三个)对于小到这个小的情况是合理的。然而,拥有数百行的功能并且在整个过程中散布着多个“纾困点”将是一件坏事。
答案 13 :(得分:0)
多年来,我一直在用自己的代码进行辩论。我开始倾向于一次回归并慢慢失效。
在这种情况下,我更喜欢选项2(一个返回),因为我们只讨论由if()包装的7行代码而没有其他复杂性。它更具可读性和功能性。它从上到下流动。你知道你从顶部开始到底部结束。
话虽如此,正如其他人所说,如果一开始有更多的警卫或更复杂或功能增长,那么我更喜欢选项1:在开始时立即返回进行简单验证。