рефакторинг нескольких условных операторов if-else в методе - PullRequest
3 голосов
/ 01 августа 2009

Я в процессе рефакторинга моего существующего кода. На самом деле он работает нормально, но немного перегружен множеством условных операторов 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 ]

6 голосов
/ 01 августа 2009

Классический ответ на рефакторинг условных выражений - Заменить условное на полиморфизм . В этом случае, если каждый из 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());
    }
}
5 голосов
/ 01 августа 2009

По крайней мере, с 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
}

Но когда enum является самоссылочным, вы должны быть осторожны с порядком объявления ваших экземпляров. Т.е. у этого будут некоторые проблемы:

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
}

Так что, если вам нужен круговой набор ссылок между перечислениями, вам придется придумать что-то еще, но если нет, вы могли бы использовать эту технику, хотя вам, возможно, придется заказать ваши экземпляры перечислений просто так, чтобы заставить его работать.

1 голос
/ 01 августа 2009

Вы можете использовать простую карту:

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