什么时候为小型重复代码段创建函数/方法,这是什么好代码实践?


12

在编写大型程序的过程中,我曾多次问过将代码放入一个函数或方法中有意义多少次复制和粘贴,什么是良好的经验法则?我一直在使用四行或更多行的经验法则,出现两次以上,然后创建包含该代码的简单函数/方法。您能想到更好的做法还是提供任何指示?这更多的是一般设计模式问题,而不是语言特定的问题。

Answers:


29

我部分使用函数作为记录代码的一种方式。调用具有有意义名称的函数可以更轻松地理解代码。在某些情况下,甚至单行的函数也是有意义的。

例如,在Clean Code中,Robert C. Martin提供了以下示例:您希望看到哪一个?这个:

// Check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) &&
    (employee.age > 65))

或这个?

if (employee.isEligibleForFullBenefits())

我并不总是同意他的观点,但在这种情况下,我同意。代码应该是可读的,不仅在您编写代码并且知道每个细节时,而且在晚上9点(当您必须修复他人代码中的错误时)也应该可读。不建议长时间凝视并尝试找出所有双重否定词。如果您可以在上面加上名称(不仅是条件,还可以是您编写的每段代码),它就会变得简单得多。

我从不后悔在函数中添加某些内容,如果您担心性能,请首先进行介绍。


2
遵循这种简单的实践,最终将使您能够以较高的水平编写应用程序代码。小功能被收集到小类中,很快您就将功能规范转换为几乎逐字逐句的代码。
凯文·克莱恩

11
我喜欢这个例子。突然,您不再需要该评论。这是一个经验法则:如果您的注释可以转换为变量或函数名称,请执行!
卡罗里·霍瓦斯

我在这里同意omrib,这通常是关于清理代码的原因,这使它比其他任何经验法则都更具可读性。如果最终还是要重用某些内容,则将其提取为一种方法。但是,我的IDE和工具通常对此有所帮助,因此操作起来既简单又快速。
特拉维斯

+1这种代码甚至可以更快,至少在需要JIT编辑的情况下-您只需为使用的代码付费。
工作


13

普遍存在误解,即仅应避免重复代码段来进行函数调用。我的经验法则是,即使仅在单个位置使用逻辑上的任何工作单元,也应将其制成一个函数。这通常可以提高可读性,并允许您编写自文档代码,其中函数名代替注释,而您无需编写其他注释来解释您的工作。


1
看看程序员为了避免写评论会花多长时间?
阿尔及尔(Alger)

1
@Alger,如他们所愿
MatrixFrog

6

如果它超过使用一个地方,

  • 可能会改变,或者
  • 正确是很棘手的

然后使其成为函数或方法。根据我的经验,一长段重复的代码自然会属于这些类别之一(通常是第一个类别,但随后的类别重叠很多;)。当然,接口中必须包含的任何内容本身也是一种功能/方法。


3
问题是:即使正确执行或可能更改的过程并不棘手,您为什么不为通常重复的代码编写函数?(我的经验法则:如果重复并且更长然后调用一个函数,则使其成为一个函数)
Winston Ewert

我会走得更远。作为程序员,您必须消除各种重复。无论是在数据库中(规范化),一些手动测试(将其替换为单元测试)还是部署(使其自动化)。
2011年

@Winston:取决于所使用的语言。并非每个构造都可以自然地捕获为一个函数,该函数可能比原始代码占用更多空间(请考虑C并通过指针返回),函数调用可能会产生开销。
弗雷德·富

@larsman,我很好奇您所指的是“(考虑C并通过指针返回)”。但是,您的意思是我试图凭经验得出的结论。调用函数必须比实现函数的内容更容易(即自然地捕获并占用更少的空间)。
温斯顿·埃韦特

如果一段代码计算多个值,比如float xint ydouble density,然后设置这些计算为C函数可不仅仅是重复的代码麻烦,因为你必须想出一个办法,让所有三个值了。如果重复计算本身是小事,它有时最好还是让他们在线。
弗雷德·富

4

几乎总是这样,特别是如果每​​个重复从概念的角度表示相同的操作。如果以相同的方式执行此操作,但对不同的类型执行此操作,则进行通用实现。

我不能想到的唯一原因是维护之一:有时,即使在某些重复的情况下,避免在单独的事物之间建立依赖关系可能更为方便。


谨防鸭子输入,如果现在实现类似,但是功能实际上不同,那么将两者合并会使恼人的分裂。特别是在IDE支持较差的语言中(嘿,我使用C ++进行工作……)
Matthieu M.

另一方面,通过将它们分开,您有两个函数可以执行相同的测试,代码被执行的可能性为一半,两个错误可能在同一地方蔓延,您必须记住修复其中的一个错误。该错误尚未被发现。我想仍然使用C ++,尽管IDE支持不佳;-)
Nicola Musatti 2011年

1

搜索“ 重构 ”将使您获得许多用于此非常常见过程的行业“最佳实践”的资源。一篇颇有名气的文章“ 一次又一次”是一个很好的历史参考资料,它解释了您的问题所引起的关注是什么“最佳实践”观点。同样,更笼统的概念称为“ 不要重复自己”(DRY)。有关问题的真正答案,请阅读Martin Fowler的经典著作《重构:改进现有代码的设计》,其中涵盖了一些最著名的重构建议,这是您直观地尝试完成的工作!


0

如果代码在多个位置精确重复,并且重复的部分在不久的将来不会更改,那么我将其分解为一个函数。


1
如果它要改变,甚至还有更多理由将其重构。然后,您只需要更改一次即可
2011年

0

这取决于重复代码的内聚性。如果重复的代码段正在执行特定功能,那么它很适合用作一种方法,部分是由于DRY原理,部分是因为如果需要优化或更正功能,则只有一个部分代码要处理。

如果关联是偶然的,则最好重复代码而不是使其成为一种方法。如果需要在代码序列之一的中间添加一些内容以满足该代码段的一种用法(如果在方法中),则所做的更改可能会影响该方法的其他用法。

请参阅Wikipedia上有关代码内聚概念的文章。


如果关联看起来是巧合,则这两个过程可能确实有一个共同的想法,您可能应该探索这两个过程是否确实是同一事物的两个方面。通常是这样。
Lie Ryan

0

您必须区分结构化编程意义上的函数和类的方法。

在您的示例中,您显示的是一种方法,因此不应进行内联编码。

您可能必须验证字符串以查看它是否为数字,在这种情况下,您将使用函数,并且前面的大多数答案都适用。

这种区别在大型项目中尤其重要。

尽您所能,将业务规则(即方法)与计算算法(即纯编程功能)分开。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.