代码重复与多负责任的方法


11

我尝试遵循“单一职责原则”(SRP),并且也省略代码重复。但是,通常在某些地方存在代码重复,这些代码重复不过是调用的代码块,这些代码块无法将其提取到至少有意义的命名方法中:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

将此类代码提取到方法中的最佳方法是什么?如何命名?


1
为什么它们拒绝提取成其他有意义的方法?
Chandranshu

所有动作都无关紧要。我将不得不写:void MethodThatDoAction1ThenAction2AndAction3IfValueAndThenAction4()。我希望在中看到更多含义CodeBlock1()
yBee

4
然后,这只是正确命名提取的方法的问题,对吗?恐怕没有通用的解决方案,您必须根据具体情况进行。如果要在一个以上的地方重复同一段代码,那么您的动作肯定会有含义,您需要努力(可能会讨论)以找到含义并给它起个名字。
Chandranshu

1
如果可以的话,长类名称的春季获奖者AbstractInterruptibleBatchPreparedStatementSetter仅比您的方法小一点。
Chandranshu

1
@Chandranshu我相信您的评论可以很好地回答这个问题。
西蒙·佛斯伯格

Answers:


13

我认为这只是正确命名提取的方法的问题。恐怕没有通用的解决方案,您必须根据具体情况进行。如果要在一个以上的地方重复同一段代码,那么您的动作肯定会有含义,您需要努力(可能会讨论)以找到含义并给它起个名字。

如果有什么安慰的话,那么长类的春季获奖者是AbstractInterruptibleBatchPreparedStatementSetter49个字符。


11

实际上,您正遭受程序员最艰巨的任务 - 命名事物Naming Things)。对不起,这么大胆的回答,但我无法抗拒。您会发现很多人都遭受这种困扰,即使在互联网上,您也可以找到这类文章

现在,如果您的重复代码全部一起完成一项工作,而这些方法没有被其他方法使用,那么它们只是简单的Helpers方法,然后可以将结果方法命名为doXXXmakeXXX...。我想您明白了。

正如Chandranshu所说:“如果您要重复这个意思并给它起个名字。” 是关键和适当的。

在此处输入图片说明

图片提供:CodeChef Facebook页面照​​片


2

我认为您对代码重复原则的理解太过分了。考虑一下避免代码重复的意义。关键是减少逻辑更改时必须检查的代码量,并通过排除明显相似的块来提高理解度。

为避免重复而进行分解的缺点是,如果必须更改共享块之一,那么现在您需要更复杂的继承或在标准和非标准实现之间进行一些切换。

因此,请仔细权衡即使其中一个块发生更改而没有其他块发生逻辑变化的可能性,也要权衡将这种共同性排除在外而获得的理解优势。如果一个实现可以与其他实现分开,那么简单地重复代码可能会更好。

在维护这些重复的代码时,随着它变得越来越复杂并且您的问题域变得更加定义,您可能会发现将重复的,现在更加复杂的,但更加定义的部分分解出来更为合适。

我通常会尝试保持文本编辑器的相同性一段时间,直到我看到看起来重复的内容是否值得考虑。我只是保持重复,但是通过保持文本在文本上易于以后匹配,我一直盯着那个块的未来。

很多时候,相同性和可能的​​分解因实际的,反复无常的业务规则和高度依赖的(通常是任意的)逻辑而消失了;就像处理几种常见的数据库实现(ANSI_NULLS或想到的一些这样)的怪癖一样;迫使看似纯粹的逻辑陷入混乱的混乱之中,在面对行业现状的混乱时,试图提供合理的,可辩护的决策逻辑。

在我看来,如果人们试图排除您要考虑的因素,我们将拥有一个像Do1Then2If2False Do1IfTrueDo2这样毫无价值的结构的完整库。

必须更复杂,更清楚地知道,该块不会改变以保证将其排除在外。

它是软件。您可以返回并编辑几个现在相同的块。这需要5分钟。而且,您只需保留它,并确保您拥有一个好的抗RSI键盘,就可以节省数小时的浪费因数,然后节省数小时的继承和切换开发。


我喜欢提取代码重复本质的部分:减少逻辑更改时必须检查的代码量
yBee 2013年

1

如果您真正遵循单一职责原则,那么此代码块必须具有特定的目的,对吗?否则,这些方法将在单独的类中。

那么,此代码块的目的是什么?确定这一点,您应该就能想到一个名字。

如果您仍然无法弄清楚这个东西的名称,那么也许这些方法实际上根本不属于一起。即,此类/代码块有多个职责。在这种情况下,重构以拆分任务可能会显示更好的目的公开名称。


1

我遇到的情况可能与您的情况类似:

有一个类定义了它代表的对象的功能:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

然后有一个类定义了对象执行的高级操作的工作流:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

如果您处于类似情况,请确定您的类表示什么(在本例中为功能/工作流程),然后相应地命名方法。

免责声明:本示例中使用的类名非常不准确,但是方法名提供了线索。建议谨慎行事。

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.