如何避免代码重复?

时间:2012-01-27 12:26:07

标签: java design-patterns code-duplication flow-control

在这种情况下是否可以避免代码重复? (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()的方法。 (可能在其他编程语言中)

6 个答案:

答案 0 :(得分:4)

一些好的答案(特别是@ Garrett刚刚提到)一个棘手的问题,但我会为后代加上0.02美元。

关于如何在不看实际代码的情况下重构这个块,这里没有简单的答案,但我对它的反应是它需要重新设计。

  

例如,一种叫做休息的方法;从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;
        ...
    }
 }

希望其中一些有帮助,祝你好运。

答案 1 :(得分:2)

避免这种重复的最好办法就是不要让你的方法保持小而专注,从而让它发生。

如果// some code here块不是独立的,那么您需要在有人可以帮助您重构之前发布所有代码。如果它们是独立的,那么就有办法重构它。

答案 2 :(得分: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()则在distinguished()中进行硬编码。但是,区分()只能由f()使用。使用Java< = 7,您需要使用带有方法invoke()的接口,而使用4个实现codeBlock1到codeBlock4。当然,这种方法根本不是可读的,但是很通用,它可以用于codeBlocks中的任何业务逻辑,甚至任何break / return / continue-orgy。

答案 3 :(得分:0)

不是真的。 第二个继续是多余的(无论如何你的代码都会继续)。 尝试使用Switch语句。它将使您的代码更具可读性。

答案 4 :(得分: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;


}

答案 5 :(得分:0)

您可能想要考虑将您的逻辑重新制定为状态机。它可能会简化事情,并可能使逻辑更容易理解。