2010-09-05 10 views
12

Tengo varios casos y solo estoy usando bloques simples if ... if else.Mejorar el código de Java: demasiados si es

¿Cómo puedo reducir el número de declaraciones if en este código?

Quizás podría usar una tabla de búsqueda, pero no estoy seguro de cómo implementarla en 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; 
} 
+12

¡Mire tantos números mágicos! Considere el uso de algunas constantes con nombre en lugar de 1, 2, 3, 4, 5, 6, etc. Porque en 6 meses, nadie recordará lo que se suponía que significaban 1 o 2. –

+1

Gracias por la ayuda de todos. Aunque no pude aceptar todas las soluciones, aprendí un poco más sobre la codificación de cada una de sus respuestas, así que agradezco mucho la ayuda. Que tengas un buen domingo. – PFranchise

Respuesta

32

Lo que estás tratando de hacer se parece mucho a una máquina de estados finitos, y estos generalmente se implementan con la ayuda de una tabla de transición. Una vez que configura la tabla, simplemente se trata de indexar la posición en la que desea obtener el valor de retorno. Suponiendo que los valores de retorno son todos menores que 256, puede usar una matriz de bytes 2D:

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

+1 - Exactamente, muy agradable. – duffymo

+0

Jaja esto es exactamente lo que estaba buscando. En realidad, estoy implementando una máquina de estados finitos. – PFranchise

+0

Aceptaría este si fuera tú. Es, de lejos, la mejor respuesta. – duffymo

6

me cambio declaración sería mejor aquí:

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

Y una nota, hay solamente 5 si los estados financieros haya comprobar números enteros puros, esto no es exactamente una sobrecarga.

+0

@RobertPitt ¡Gracias! Agradezco los comentarios adicionales. – PFranchise

+0

actualizado para completar su lógica. – RobertPitt

+0

para reducir aún más el código, si utiliza los lógicos de mano cortos y los mantiene en 1 línea, puede eliminar los comandos 'break;', SI java tiene eso dentro de su intérprete. – RobertPitt

9

consideran Interfaces + enumeraciones:

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

Uso switch declaración para la cadena de if exterior:

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

Bueno, se puede utilizar fácilmente hash. Simple y limpio.

// 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; 
+0

En cuanto al rendimiento, ¿no sería mejor crear una clase nueva que contenga un dígito y un carácter y que tenga una función hash que genere un hash único para que la tabla hash pueda funcionar más rápido? – alternative

+0

@mathepic Sin duda, hay mucho margen de mejora.(Aunque puede descubrir que la creación de una función hash única no siempre es fácil, especialmente a medida que aumenta el número de estados). Solo quería proporcionar un ejemplo simple y limpio de la tabla de búsqueda. Y no es como HashMap tiene tanta sobrecarga en comparación con otros métodos, como matrices de una o dos dimensiones. –

+0

Sí, solo estaba haciendo una sugerencia. +1. – alternative

5

Parece que necesita una mejor abstracción para una máquina de estados finitos. Piense en una clase que encapsule lo que desea de una mejor manera para que pueda extenderla por configuración en lugar de modificar el código.

+0

Gracias por el consejo. Estaba preocupado de que estuviera codificando demasiado. Voy a reconsiderar la forma en que lo estoy haciendo. – PFranchise

+0

+1 En mi humilde opinión la mejor sugerencia aquí. Cuando veo un montón de ifs, lo primero que me viene a la mente es 'Use Inheritance'. – helpermethod

+0

Como regla general, puede * siempre * reemplazar condiciones con polimorfismo. Después de todo, ¿qué * es * envío de método dinámico si no es una declaración de cambio gigante? Smalltalk, por ejemplo, no tiene * ningún * condicional, * todo * se realiza a través del envío del método. –

5

Si este código está a punto de expandirse con el tiempo, ¿por qué no utilizar una máquina de estados? Cada estado devolverá el próximo estado en función del personaje que reciba. Tal vez es un exceso para este código, pero será mucho más fácil de mantener, expanda & de lectura.

+0

¡El código casi siempre cambia! –

Cuestiones relacionadas