在方法中重构多个if-else条件

时间:2009-07-31 22:37:28

标签: java refactoring conditional

我正在重构现有代码。它实际上工作正常,但它有点混乱,多个if-else条件检查一个变量的值,并将第二个变量的值更改为从固定枚举结构中获取的更新值。

else if (var1 == 'valueX')
{
    if (var2 == MyEnum.A)
        var2 = MyEnum.B;
    else if (var2 == MyEnum.B)
        var2 = MyEnum.C;
    else if (var2 == MyEnum.C)
        var2 = MyEnum.D;
    else if (var2 == MyEnum.D)
        var2 = MyEnum.A;
}

else if (....)
{
..similar block of conditionals
}

我对重构和清理此代码的最佳方法有点困惑。你会建议使用开关吗?还是更优雅的东西?

提前致谢!

3 个答案:

答案 0 :(得分:6)

重构条件的经典答案是Replace Conditional With Polymorphism。在这种情况下,如果每个MyEnum都知道它的继承者是什么,你可以简单地说(在'valuex'的情况下:var2 = var2.successor。对于var1 - 如果它可能是一个实现了一个知道如何处理的接口的对象无论你在循环中做什么,每个实现类都知道它应该做什么......好吧,你已经完成了。

<强>更新

在测试用例中,这是一个花花公子的小继承函数:

public class EnumTest extends TestCase {
    private enum X {
        A, B, C;
        public X successor() {
            return values()[(ordinal() + 1) % values().length];
        }
    };

    public void testSuccessor() throws Exception {
        assertEquals(X.B, X.A.successor());
        assertEquals(X.C, X.B.successor());
        assertEquals(X.A, X.C.successor());
    }
}

答案 1 :(得分:5)

至少使用J2SE 1.5转发,您可以为枚举提供额外的属性。这意味着您可以将整个if-else字符串替换为类似

的内容
var2 = var1.getNextInSequence();

现在,在这种情况下,看起来您希望该属性是对另一个枚举的引用,这会增加一些皱纹,例如,在初始化它们时无法转发引用枚举,但可能有一个可行的解决方案就是这样。

当属性不是同一枚举的其他实例时,这种事情会起作用:

public enum Animal {
    FOX(4),
    CHICKEN(2),
    WORM(0);

    private int countLegs;

    Animal(int n) {
        countLegs = n;
    }

    public int getLegCount() {
        return countLegs;
    }
    // .. more getters setters etc
}

但是当枚举是自我指涉的时候,你必须要小心你的实例的声明顺序。即,这将有一些问题:

public enum Animal {
    FOX(4, CHICKEN),    // 'CHICKEN' doesn't exist yet
    WORM(0, null),
    CHICKEN(2, WORM);    // this actually will compile

    private int countLegs;
    private Animal eatsWhat;

    Animal(int n, Animal dinner) {
        countLegs = n;
        eatsWhat = dinner;
    }

    public int getLegCount() {
        return countLegs;
    }
    // .. getters, setters, etc
}

因此,如果您需要在枚举中使用循环引用,则必须使用其他内容,但如果不是,则可以使用此技术,但您可能需要订购你的枚举实例只是为了让它工作。

答案 2 :(得分:1)

您可以使用简单的地图:

enum MyEnum { A, B, C };

Map<MyEnum, MyEnum> VALUE_X = new HashMap<MyEnum, MyEnum>() {{
    put(MyEnum.A, MyEnum.B);
    put(MyEnum.B, MyEnum.C);
    ...
}};

// define another kind of ordering
Map<MyEnum, MyEnum> VALUE_Y = new HashMap<MyEnum, MyEnum>() {{
    put(MyEnum.A, MyEnum.D);
    put(MyEnum.B, MyEnum.A);
    ...
}};

这样,下一个var2值的逻辑在枚举本身中不是硬编码的,并且可以依赖于上下文(即var1的值):

if ("valueX".equals(var1)) {  // use equals() instead of == for Strings
    var2 = VALUE_X.get(var2);
}
else if ("valueY".equals(var1)) {
    var2 = VALUE_Y.get(var2);
}