如何避免代码重复?

问题描述 投票:5回答:6

在这种情况下是否可以避免代码重复? (Java代码)

void f()
{
    int r;
    boolean condition = true;
    while(condition)
    {
        // some code here (1)

        r = check();
        if(r == 0)
            break ;
        else if(r == 1)
            return ;
        else if(r == 2)
            continue ;
        else if(r == 3)
            condition = false;

        // some code here (2)

        r = check();
        if(r == 0)
            break ;
        else if(r == 1)
            return ;
        else if(r == 2)
            continue ;
        else if(r == 3)
            condition = false;

        // some code here (3)
    }
    // some code here (4)
}

int check()
{
    // check a condition and return something
}

可能的解决方案可能是使用异常,但这似乎不是一个好习惯。在这种情况下,是否存在所谓的良好程序流控制模式?例如,一种从break ;函数内部调用check()的方法。(可能是其他编程语言)

java design-patterns code-duplication control-flow
6个回答
4
投票

对于一个棘手的问题,有一些好的答案(特别是@Garrett的问题,但我将为后代添加$ 0.02。

这里没有关于如何重构此块而没有看到实际代码的简单答案,但我对此的反应是,需要重新设计它。

例如,调用break的方法;从check()函数内部。 (可能是其他编程语言)

[如果您要请求Java不支持的其他中断(没有技巧),并且具有重复的check()和各种不同的循环退出/重复代码,则对我来说,这是一个庞大而复杂的方法。以下是一些您可以考虑的想法:

  • some code here的每个块都在做某事。如果将它们拉出自己的方法,那将如何改变循环?

  • 也许将循环分解为一系列注释。不要深入研究代码,而是从概念上进行思考,以查看是否有其他配置退出。

  • 您的组织中是否有其他开发人员不参与此代码的研究?如果您详细解释了某人的代码工作方式,他们可能会看到某些模式,因为您处于杂草状态。

[我也认为@aix的有限状态机是个好主意,但我在编程过程中很少需要使用这种机制,主要是在模式识别期间。我怀疑重新设计代码,将较小的代码块放入方法中就足以改善代码。

如果您确实想实现状态机,这里有更多详细信息。您可能有一个循环,该循环仅运行一个称为方法的单个switch语句。每个方法将为开关返回下一个值。这与您的代码不完全匹配,但类似于:

int state = 0;
WHILE: while(true) {
    switch (state) {
       case 0:
            // 1st some code here
            state = 1;
            break;
       case 1:
            state = check();
            break;
       case 2:
            return;
       case 3:
            break WHILE;
       case 4:
            // 2nd some code
            state = 1;
            break;
        ...
    }
 }

希望其中一些帮助和好运。


2
投票

避免这种重复的最佳方法是,不要通过使方法小型化和集中化而让它首先发生。

如果// some code here块不是独立的,那么您需要发布所有代码,然后其他人才能帮助您重构它。如果它们是独立的,则有一些方法可以对其进行重构。


1
投票

代码气味

首先,我第二个aix的答案:重写您的代码!为此,state design pattern可能会有所帮助。我还要说的是,以这种方式使用break,continue和return就像代码重复本身一样具有代码异味。

话虽如此,这是一个解决方法,只是为了好玩

private int r;
void f()
{
    distinction({void => codeBlock1()}, {void => codeBlock4()}, {void => f()}, 
      {void => distinction( {void => codeBlock2()},{void => codeBlock4()},
                            {void => f()}, {void => codeBlock3()} )
      });
}

void distinction( {void=>void} startingBlock, {void=>void} r0Block, {void=>void} r2Block, {void=>void} r3Block){ 
        startingBlock.invoke();
        r = check();
        if(r == 0)
            r0Block.invoke();
        else if(r == 1)
            {}
        else if(r == 2)
            r2Block.invoke(); 
        else if(r == 3)
            // if condition might be changed in some codeBlock, you still
            // would need the variable condition and set it to false here.
            r3Block.invoke();
}

这使用闭包。当然,可以省略参数r0Block和r2Block,而将codeBlock4()和f()硬编码在difference()中。但是,则只有f()可以使用discprise()。在Java <= 7的情况下,您需要将Interface与方法invoke()结合使用,并使用4种实现codeBlock1至codeBlock4。当然,这种方法根本不可读,但是它是如此笼统,以至于它适用于codeBlocks中的任何业务逻辑,甚至适用于任何break / return / continue-orgy。


0
投票

不是。第二个继续是多余的(您的代码仍然会继续)。尝试使用Switch语句。这将使您的代码更具可读性。


0
投票

一种更好的方法是使用switch语句,如下所示:

void f()
{
int r;
boolean condition = true;
while(condition)
{
outerloop:


    r = check();
    switch(r){

    case 0: break outerloop;

    case 1: return;

    case 2: continue;

    case 3: condition  = false;


}

0
投票

您可能想考虑将逻辑重新构造为状态机。它可以简化事情,并且可能使逻辑更容易遵循。

© www.soinside.com 2019 - 2024. All rights reserved.