【问题标题】:refactoring multiple if-else conditionals in a method在方法中重构多个 if-else 条件
【发布时间】:2010-11-15 22:59:24
【问题描述】:

我正在重构我现有的代码。它实际上工作正常,但它有点混乱,有多个 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
}

对于重构和清理此代码的最佳方法是什么,我感到有些困惑。你会建议使用开关吗?或者更优雅的东西?

提前致谢!

【问题讨论】:

    标签: java refactoring conditional


    【解决方案1】:

    重构条件的经典答案是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());
        }
    }
    

    【讨论】:

    • 感谢更新!这看起来真的很有趣。会试一试的。
    • 您的代码中没有多态性。当然,在这种情况下,它显然比定义 successor 三次要好,但你应该说清楚。
    • 我明白你的意思,@maaartinus:这不是通过继承实现的经典多态性,但我不同意。当两个不同的实体仅仅因为它们是什么而表现不同时,这就是所讨论的目的的多态性。
    【解决方案2】:

    至少在 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
    }
    

    因此,如果您需要枚举之间的循环引用集,则必须解决其他问题,但如果不需要,您可以使用这种技术,尽管您可能必须这样做订购您的枚举实例以使其正常工作。

    【讨论】:

    • 感谢您的分析!所以基本上我需要创建一个方法来从我的枚举中依次获取下一个。
    【解决方案3】:

    您可以使用简单的地图:

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-26
      • 2021-11-20
      • 1970-01-01
      • 1970-01-01
      • 2021-03-07
      • 2016-08-05
      • 1970-01-01
      • 2020-05-31
      • 2014-09-06
      相关资源
      最近更新 更多