Улучшение Java-кода: слишком много if - PullRequest
12 голосов
/ 05 сентября 2010

У меня есть несколько дел, и я просто использую простые 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;
}

Ответы [ 7 ]

32 голосов
/ 05 сентября 2010

То, что вы пытаетесь сделать, очень похоже на конечный автомат, и они обычно реализуются с помощью таблицы переходов. После того, как вы настроите таблицу, вам нужно просто проиндексировать позицию, которую вы хотите получить. Предполагая, что все возвращаемые значения меньше 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];
}
14 голосов
/ 05 сентября 2010

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

    // 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;
9 голосов
/ 05 сентября 2010

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

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);
   }
}
6 голосов
/ 05 сентября 2010

Здесь лучше всего использовать оператор 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, если операторы там проверяют чистые интергеры, это не совсем накладные расходы.

5 голосов
/ 05 сентября 2010

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

5 голосов
/ 05 сентября 2010

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

2 голосов
/ 05 сентября 2010

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

switch (state) {
  case 0: <code> ; break;
  case 1: <code> ; break;
  case 2: <code> ; break;
  <etc>
  default: return 0; break;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...