繁体   English   中英

如何避免代码重复?

[英]How to avoid code duplication?

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

对于一个棘手的问题,有一些很好的答案(尤其是刚刚@Garrett 的),但我会为后代添加我的 0.02 美元。

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

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

如果您要求 Java 不支持的不同中断(没有 hack)并且具有重复的check()和各种不同的循环退出/重复代码向我表明这是一个庞大而复杂的方法。 这里有一些想法供您思考:

  • some code here每个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;
        ...
    }
 }

希望其中的一些帮助并祝你好运。

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

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

代码异味

首先,我第二个 aix 的回答:重写你的代码! 为此,状态设计模式可能会有所帮助。 我还要说,以这种方式使用 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() 硬编码在 distinct() 中。 但是,distinct() 只能被 f() 使用。 对于 Java <=7,您需要使用带有方法 invoke() 的接口,以及代码块 1 到代码块 4 的 4 个实现。 当然,这种方法根本不可读,但非常通用,它适用于 codeBlocks 中的任何业务逻辑,甚至任何中断/返回/继续狂欢。

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

一种更好的方法是使用 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;


}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM