Подтвердить что ты не робот

Улучшите код Java: слишком много if

У меня есть несколько случаев, и я просто использую простые блоки if ... if else.

Как уменьшить количество операторов if в этом коде?

Возможно, я мог бы использовать таблицу поиска, но я не уверен, как ее реализовать на Java.

private int transition(char current, int state)
{
    if(state == 0)
    {
        if(current == 'b')
        {
            return 1;
        }
        else 
            return 0;
    }
    if(state == 1)
    {
        if(current == 'a')
        {
            return 2;
        }
        else 
            return 0;
    }
    if(state == 2)
    {
        if(current == 's')
        {
            return 3;
        }
        else 
            return 0;
    }
    if(state == 3)
    {
        if(current == 'e')
        {
            return 3;
        }
        if(current == 'b')
        {
            return 4;
        }
        else 
            return 0;
    }
    if(state == 4)
    {
        if(current == 'a')
        {
            return 5;
        }
        else 
            return 0;
    }
    if(state == 5)
    {
        if(current == 'l')
        {
            return 6;
        }
        else 
            return 0;
    }
    else
        return 0;
}
4b9b3361

Ответ 1

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

byte table[][] = new byte[NUM_STATES][NUM_CHARACTERS];
// Populate the non-zero entries of the table
table[0]['b'] = 1;
table[1]['a'] = 2;
// etc...

private int transition(char current, int state) {
  return table[state][current];
}

Ответ 2

Ну, вы можете легко использовать hash. Простой и чистый.

    // declare hashtable
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("0-b", 1);
    map.put("1-a", 2);
    map.put("2-s", 3);
    ...

    // get result
    Integer result = map.get(state + "-" + current);
    // change null (nothing found) to zero
    return result == null ? 0 : result;

Ответ 3

рассмотрим интерфейсы + перечисления:

interface State<T>
{
    public void State<T> step(T input);
}

enum MyState implements State<Character> {
    STATE0(0) { @Override public void MyState step(Character c) { return c == 'b' ? STATE1 : STATE0; }},
    STATE1(1) { @Override public void MyState step(Character c) { return c == 'a' ? STATE2 : STATE0; }},

    /* rest of states here */

    final private int value;
    MyState(int value) { this.value = value; }
    public int getValue() { return this.value; }
}

class SomeClass
{
   public MyState currentState = STATE0;

   public void step(char input)
   {
      this.currentState = this.currentState.step(input);
   }
}

Ответ 4

i оператор switch будет лучше:

private int transition(char current, int state)
{
    switch(state)
    {
        case 0:
            return current == 'b' ? 1 : 0;
        case 1:
            return current == 'a' ? 2 : 0;
        case 2:
            return current == 's' ? 3 : 0;
        case 3:
            return current == 'e' ? 3 : (current == 'b' ? 4 : 0);
        case 4:
            return current == 'a' ? 5 : 0;
        case 5:
            return current == 'l' ? 6 : 0;
        default:
            return 0;
    }
}

И примечание: только 5, если утверждения там проверяют чистые intergers, это не совсем накладные расходы.

Ответ 5

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

Ответ 6

Если этот код будет расширяться с течением времени, почему бы не использовать конечный автомат? Каждое состояние будет возвращать следующее состояние на основе получаемого им символа. Возможно, это лишний для этого кода, но будет намного проще поддерживать, расширять и читать.

Ответ 7

Используйте инструкцию switch для внешней цепи if:

switch (state) {
  case 0: <code> ; break;
  case 1: <code> ; break;
  case 2: <code> ; break;
  <etc>
  default: return 0; break;
}