【问题标题】:When should we create a new method?我们什么时候应该创建一个新方法?
【发布时间】:2009-11-17 15:02:20
【问题描述】:

我正在尝试找出是否就何时应该在代码中创建新方法达成共识。例如,如果我们要再次使用代码(因此我们显然减少了使用的行),我们应该只创建一个新的方法/函数,还是为了避免代码混乱而这样做是常见的。我已经编程很长时间了,但我真的只是进入并以相当随机的方式做出决定。

是否有任何设计模式或书籍可以解决这个问题?一个相关的问题是我们是否应该只使用 getter 和 setter 方法在对象中设置参数。这显然会创建更多代码,但会使事情更易于管理?对此有何共识?

【问题讨论】:

    标签: design-patterns oop


    【解决方案1】:

    我认为对此没有具体的设计指南。但有些设计原则确实谈到了方法创建。

    DRY(不要重复自己)是方法创建的指导原则。您将相似的逻辑分组到一个方法中,这样您就不会在整个代码中重复它们,从而使维护成为一场噩梦。

    Single Responsibility Principle 是另一个。它说你的类或方法应该只做一个的事情。这是为了使方法大小变小。

    【讨论】:

    • 另外,如果一个方法变得非常冗长和复杂,它有助于将其分解为更小的函数,以使其更易于管理,即使这些部分不会被重用。
    • +1,虽然单一职责原则实际上只适用于类。
    • SRP 是一个很好的遵循原则,但请确保将其视为指导原则,很多时候将方法分组到有意义的类中是有意义的,即使它会违反 SRP。然而,DRY 是一种更接近于编程法则的约定。代码重复从根本上来说是阴险的,应尽可能避免。
    • 这方面的另一个方面是方法有名称,名称可以非常具有描述性,并用于记录代码。因此,将代码块重构为具有描述性名称的方法可能是朝着更多自文档化代码迈出的一步。我已经多次使用并且看到它用于这个特定目的,并且发现它是一个非常有用的工具,用于寻求可读和可维护的代码。
    • 总结:只有一件事应该做一件事。
    【解决方案2】:

    我将编程视为一门艺术。因此,当 感觉正确 拆分方法或编写新方法时,我会拆分方法。

    也就是说,有一些经验法则(不会推翻我的直觉)。

    1. 如果需要滚动屏幕阅读一种方法,则需要拆分它
    2. 如果您有 deja vue(您编写的代码似乎很熟悉),您可能是在重复自己,这意味着您应该使用现有的函数/方法,而不是编写新的。

    3. 深度不超过两个构造

      对于(...) 为了(...) 对于(...)不好

    4. 连续循环不超过一个(一个接一个)。

    5. 如果您需要返回不止一种类型的数据(null/false 版本不是),那么您需要拆分一些内容。
    6. 如果您在阅读方法时感到困惑 - 拆分它
    7. 一个方法/函数应该负责一项任务。
    8. 最明显的 - 在编写新功能时 :-)

    【讨论】:

    • 很好,这是一份很好的具体指导方针清单,让我立即想到了我的一些信息,尤其是“如果您需要返回一种以上类型的数据”。
    【解决方案3】:

    一个有趣的观点,尽管与面向对象编程无关,是在 linux 的编码风格guide:

    第 4 章:函数

    函数应该简短而有趣,并且只做一件事。它们应该适合一屏或两屏文本(众所周知,ISO/ANSI 屏幕尺寸为 80x24),并且做好一件事。

    函数的最大长度与该函数的复杂度和缩进级别成反比。所以,如果你有一个概念上简单的函数,它只是一个很长(但很简单)的 case 语句,你必须为很多不同的情况做很多小事情,那么有一个更长的函数是可以的。

    但是,如果您有一个复杂的函数,并且您怀疑一个不太有天赋的高中一年级学生可能甚至不了解该函数的全部内容,那么您应该更加遵守最大限制密切。使用具有描述性名称的辅助函数(如果您认为它对性能至关重要,您可以要求编译器将它们内联,并且它可能会比您做得更好)。

    函数的另一个度量是局部变量的数量。它们不应该超过 5-10,否则你做错了什么。重新考虑该功能,并将其拆分为更小的部分。人脑通常可以轻松地跟踪大约 7 种不同的事物,再多的事物就会变得混乱。你知道你很聪明,但也许你想了解 2 周后你做了什么。

    【讨论】:

      【解决方案4】:

      如果您的方法很长,将它们重新分解为更小的块是有意义的,即使这些块没有在其他任何地方使用。这将增加可维护性和可测试性。此外,使用这种方法,您可以让其他开发人员更轻松地扩展您的代码,以防他们想要更改方法的某些职责,例如通过重载它。

      至于 getter 和 setter,这在一定程度上取决于您使用的语言。在某些语言中,这可能非常冗长。就个人而言,我只为公共属性提供 getter 和 setter,和/或如果更改属性涉及的逻辑不仅仅是设置/获取属性。

      【讨论】:

        【解决方案5】:

        如果出现以下情况,您可能想要提取方法:

        • 有一个块的注释块
        • 你可以命名一个块的意图

        【讨论】:

          【解决方案6】:

          除了优秀的answer by Graviton之外,我推荐另一个经验法则来决定何时创建新方法:

          每当您想为一段代码编写注释时,请将该代码移至专用函数中。给函数起一个描述性的名称。

          【讨论】:

            【解决方案7】:

            我认为这是一个非常主观的问题,没有真正的答案。不同的情况需要不同的解决方案,并且不会有“何时创建新方法”的单一配方。视情况而定。

            【讨论】:

            • 同意...这是“It Depends”模式的明确候选者;)
            【解决方案8】:

            当您开始在代码块之间放置双空格来表示不同的职责时。

            【讨论】:

              【解决方案9】:

              查看 Robert Martin 的 Clean Code,其中涵盖了这一点(以及其他内容)

              【讨论】:

              • @Chris 非常感谢您的建议。根据您的建议,我参与了 Robert Martin 的工作,我对他的代码有多棒感到惊讶。这真的是一项艰苦的工作。不到 8 行是我的新答案
              • 你能在哪部分找到这个?
              【解决方案10】:

              getter 和 setter OOP 不是,而且通常不仅仅是将代码大小加倍并没有好处。

              关于书籍:设计模式(Gamma、Vlissides、Johnson、Helm)、Fowler 的书籍(重构、企业应用架构模式)、Beck 的书籍(示例测试驱动开发、实现模式)等。

              【讨论】:

              • “getter 和 setter OOP 不是”中的语法错误
              • 这是一个模因变体的尝试,很抱歉造成混乱。
              【解决方案11】:

              一个方法应该做一件事,并且把它做好。它不应该比它的名字所暗示的多或少。 CustomerSave 方法也不应该规范化客户的地址。

              一个方法应该只关注一个“级别”的功能。如果在 CustomerSave 方法中出现多于一行代码用于以下各项:打开数据库、记录更改、检查安全性等,那么代码在错误的级别上运行,应该创建新的方法来处理这些东西在适当的粒度上。

              方法通常应该很短。只有在特殊情况下,一种方法才能溢出多个屏幕。如果一个方法有一百行长,那么就大错特错了。

              代码不应重复。重复的功能应该放在一个方法中。

              应该设计方法,以便可以轻松地进行典型的更改。如果需要在几十个地方进行微小的更改,那么这表明本应放在一个方法中的重复代码。

              【讨论】:

                【解决方案12】:

                我曾经听过有人说,如果一个方法/函数变得太大而无法在不滚动的情况下放在单个屏幕上,那么它应该被重构为单独的方法。

                这并不总是正确的,并且为了重构而重构没有任何价值,但通常有助于保持事物的正确性。

                【讨论】:

                  【解决方案13】:

                  对您的代码进行单元测试,并拆分方法,以便您每次可以对一个任务进行单元测试。这是减少整个问题主观性的好方法,因为它具有能够对每个任务进行单元测试的真正外部约束。

                  【讨论】:

                    【解决方案14】:

                    大多数方法应该完成一项任务。

                    【讨论】:

                    • 所有方法只完成一项任务。
                    【解决方案15】:

                    创建完成特定任务的方法。 如果方法的大小增加,则意味着它有一些子任务,因此将子任务分离(重构)到一个新方法中。

                    【讨论】:

                      【解决方案16】:

                      根据 DRY 原则(您和其他一些人已经提到过),您最终不想重复自己。它还取决于您使用的语言。许多面向对象的语言将所有方法公开(例如Objective-C),因此您只想创建旨在由其他对象调用的函数。另一方面,像 Java 这样的许多语言都提供了私有函数,这些函数支持将代码块分组为私有函数的概念,这些私有函数实际上并不打算在类本身之外使用。

                      【讨论】:

                        【解决方案17】:

                        您应该几乎总是在重复代码时创建一个新方法。

                        它会删除重复的代码,如果你选择一个好名字,它会自动记录。

                        在两个地方出现的同一行代码不会太短而不能用来制作方法,除非这行代码微不足道且其意图非常明显。

                        【讨论】:

                        • 是的,但是如果你从不重复代码,并且你有一个 300 行或更多的方法呢? , 如果我们遵循这个原则,方法永远不应该分开。这个不清楚
                        【解决方案18】:

                        为了限制最大圈复杂度,即使只调用一次,您也可以引入新方法

                        在我的脑海中,我可以列出很多提取方法的原因,但很少有将它们组合起来的原因。

                        • 显而易见,DRY, aka DIE。 在它成为很酷的首字母缩略词之前,我就遵循了这一理念。我认为任何人都不应该出于任何原因复制或复制和粘贴代码,无论它有多短。如果你这样做了,你就是在酝酿一场噩梦。
                        • 限制cyclomatic complexity. 3 种易于理解的方法比一种令人困惑的方法要好得多。即使新提取的方法仅被调用一次,此规则和其他规则也适用
                        • 提取一个功能单元进行单元测试
                        • 保持所有方法在编辑器中可见而无需滚动

                        顺便说一句,我可能会建议更改语言。 “创建一个新方法”听起来像是在代码中添加一些东西,让它变得更大更复杂。但是“提取方法”是当你重构为一个有希望的优秀设计时真正发生的事情。假设无论如何你都必须拥有那个功能,那个方法总是在那里,它只是被埋在另一个里面......

                        【讨论】:

                          【解决方案19】:

                          SLAP 和 DRY 是好的原则。请参阅此链接http://tv.devexpress.com/SLAPrule.movieJulian 先生的精彩演讲。 [好像视频网站关闭了一段时间。请稍后查看]

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2012-11-13
                            • 1970-01-01
                            • 1970-01-01
                            • 2019-04-17
                            • 1970-01-01
                            • 1970-01-01
                            • 2019-04-21
                            • 1970-01-01
                            相关资源
                            最近更新 更多