2009-09-15 20 views
6

¿Hay alguna otra forma alternativa de implementar una caja de conmutadores en Java que no sea otra que no se vea bien? Un conjunto de valores estará allí en combinación, de acuerdo con la selección, el método correspondiente debe ser ejecutado.Alternativa a la caja del conmutador en Java

+0

¿Qué quieres decir cuando dices 'Un conjunto de valores estará allí en combo'? – Alterlife

+0

ya formuladas homóloga pregunta http://stackoverflow.com/questions/126409/ways-to-eliminate-switch-in-code –

+0

@cdb: Entonces ¿por qué lo preguntas de nuevo? ¿Qué no te dijeron las respuestas anteriores? –

Respuesta

15

Es de suponer que estás luchando con el requisito de que el caso sea constante. Normalmente, este es un olor a código, pero hay cosas que puedes hacer. Es posible que desee plantear y vincular a otra pregunta que detalla por qué está tratando de cambiar.

Map<String,Object> map = new HasMap<String,Object>(); 
// ... insert stuff into map 
// eg: map.add("something", new MyObject()); 

String key = "something"; 
if (map.contains(key)) { 
    Object o = map.get(key); 
} 

En el ejemplo anterior, es posible que desee asignar a los manipuladores '', algo así como

interface Handler { 
    public void doSomething(); 
} 

que a su vez hace que esto se convierta en una búsqueda.

if (map.contains(key)) { map.get(key).doSomething(); } 

De nuevo, es un poco olor, así que por favor publique una pregunta que ilustre el razonamiento.

+2

También podría usar Enums si la constancia es un dolor. – Ibrahim

+0

buscando algo como esto. –

+1

¿Por qué contiene y luego obtiene su lectura del mapa dos veces? Comando comment = map.get (clave); if (! = Comando nulo) { ... command.execute(); } –

0

¿Qué desea hacer? ¿Por qué no es Switch-Case lo suficientemente bueno?

La respuesta rápida es: utilizar if-else

0
if() {} 
    else if() {} 
... 
    else if() {} 

?

Pero yo no diría que es mejor ...

1

una serie fea de if,else if,else?

0

¿Qué tal un if (junto con else if y else) declaración? Mientras que switch solo le permitirá cambiar usando igualdad contra enteros o tipos Enum, if le permite usar cualquier lógica booleana.

+0

char, byte, corto también se puede utilizar en los interruptores. – dogbane

+0

Sí, pero pueden también ser segura (automáticamente) echaron a int –

4

La refacturación de su código para usar polimorfismo podría eliminar la necesidad de una declaración de cambio. Sin embargo, hay algunos usos legítimos para el cambio, así que depende de su situación.

+2

Si- esto es un conocido refactoring- http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html – RichardOD

+0

Niza enlace. Parece que hay muchos buenos en el catálogo. –

0

Siempre puede reemplazar un interruptor con if-else if-else if-else if..., aunque no veo por qué lo desea. Dependiendo del contexto switch s también a veces puede ser reemplazado por matrices o hashmaps.

24

Si tiene un montón de declaraciones de interruptor/caja alrededor de su código y que están volviendo loco.

Se podría optar por el Refactoring: Replace conditional with polymorphism.

Digamos que usted tiene una pieza de software que se utiliza para guardar información en diferentes dispositivos: 4 operaciones de persistencia se definen: buscar, guardar, eliminar, actualización, que podría ser implementado por N número de mecanismo de persistencia (archivos planos, red, RDBMS, XML, etc.).

El código tiene que apoyar a todos ellos por lo que en 4 lugares diferentes que tiene la siguiente:

ANTES

class YourProblematicClass { 

.... 

    public void fetchData(Object criteria) { 

      switch (this.persitanceType) { 
       case FilePersistance: 
        // open file 
        // read it 
        // find the criteria 
        // build the data 
        // close it. 
        break; 
       case NetWorkPersistance: 
        // Connect to the server 
        // Authenticate 
        // retrieve the data 
        // build the data 
        // close connection 
        break(); 
       case DataBasePersistace: 
        // Get a jdbc connection 
        // create the query 
        // execute the query 
        // fetch and build data 
        // close connection 
        break; 
      } 
      return data; 
     }  

Lo mismo para guardar/borrar/actualización

public void saveData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       // open file, go to EOF, write etc. 
       break; 
      case NetWorkPersistance: 
       // Connect to the server 
       // Authenticate 
       // etc 
       break(); 
      case DataBasePersistace: 
       // Get a jdbc connection, query, execute... 
       break; 
     } 
    } 

Y etc.

public void deleteData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       break; 
      case NetWorkPersistance: 
       break(); 
      case DataBasePersistace: 
       break; 
     } 
    } 

public void updateData(Object data) { 

     switch (this.persitanceType) { 
      case FilePersistance: 
       break; 
      case NetWorkPersistance: 
       break(); 
      case DataBasePersistace: 
       break; 
     } 
    } 

Usando sentencia switch/case convierte en un problema:

  • Cada vez que desee añadir un nuevo tipo que tiene que insertar el nuevo interruptor/caja en cada sección.

  • Muchas veces, algunos tipos son similares, y que no necesitan un interruptor/caso diferente (se puede conectar en cascada ellos)

  • Algunos otros que son, y algunas veces difieren ligeramente
  • Usted puede aunque tenga que cargar diverso tipo en tiempo de ejecución (como plugins)

Así que la refactorización aquí habría que añadir una interfaz o tipo abstracto y tienen los diferentes tipos implementan esa interfaz y delegar la responsabilidad a ese objeto.

Así que tendría algo como esto:

DESPUÉS

public interface PersistenceManager { 
     public void fetchData(Object criteria); 
     public void saveData(Object toSave); 
     public void deleteData(Object toDelete); 
     public void updateData(Object toUpdate); 
    } 

y diferentes implementaciones

public class FilePersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
        // open file 
        // read it 
        // find the criteria 
        // build the data 
        // close it. 
     } 
     public void saveData(Object toSave) { 
       // open file, go to EOF etc. 
     } 
     public void deleteData(Object toDelete){ 
      .... 
     } 
     public void updateData(Object toUpdate){ 
      .... 
     } 
    } 

Y los otros tipos implementaría acuerdo con su lógica. La red trataría con sockets, y streams, DB trataría con JDBC, ResultSets etc. XML con node etc.etc.

public class NetworkPersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
      // Socket stuff 
     } 
     public void saveData(Object toSave) { 
      // Socket stuff 
     } 
     public void deleteData(Object toDelete){ 
      // Socket stuff 
     } 
     public void updateData(Object toUpdate){ 
      // Socket stuff 
     } 
    } 


    public class DataBasePersistence implements PersistanceManager { 
     public void fetchData(Object criteria) { 
      // JDBC stuff 
     } 
     public void saveData(Object toSave) { 
      // JDBC stuff 
     } 
     public void deleteData(Object toDelete){ 
      // JDBC stuff 
     } 
     public void updateData(Object toUpdate){ 
      // JDBC stuff 
     } 
    } 

Y finalmente solo tiene que delegar las invocaciones.

después:

public YouProblematicClass { // not longer that problematic 

    PersistamceManager persistance = // initialize with the right one. 


     public void fetchData(Object criteria) { 
      // remove the switch and replace it with: 
      this.persistance.fetchData(criteria); 
     } 
     public void saveData(Object toSave) { 
      // switch removed 
      this.persistance.saveData( toSave); 
     } 
     public void deleteData(Object toDelete){ 
      this.persistance.deleteData(toDelete); 
     } 
     public void updateData(Object toUpdate){ 
      this.persistance.updateData(toUpdate); 
     } 
    } 

Por lo tanto, sólo hay que crear la instancia correcta para el gestor de persistencia de acuerdo con el tipo de una sola vez. Entonces todas las invocaciones se resuelven por polimorfismo. Esa es una de las características clave de Object Oriented Technology.

Si decide que necesita otro administrador de persistencia, solo cree la nueva implementación y asigne la clase.

public WavePersistance implements PersistanceManager { 

     public void fetchData(Object criteria) { 
      // .... 
     } 
     public void saveData(Object toSave) { 
      // .... 
     } 
     public void deleteData(Object toDelete){ 
      // .... 
     } 
     public void updateData(Object toUpdate){ 
      // .... 
     } 
    } 
+2

Muy buena respuesta! – mac

1

o uno podría imaginar una especie de caja de conmutación dinámica:

public interface Task<T> 
    { 
    public void doSomething(T context); 
    } 

public Class SwitchCase<T> 
    { 
    Map<Integer,Task<T>> tasks; 
    Task<T> defaultTask; 

    public void choose(int choice, T context) 
     { 
     Task<T> t= this.tasks.get(choice); 
     if(t!=null) { t.doSomething(context); return;} 
     if(defaultTask!=null) { defaultTask.doSomething(context);} 
     } 
    } 
1

supongo "código limpio" tiene un capítulo agradable según switch/case vs if/else.

Además Creo que tiene sentido para decidir si se puede reducir el "ruido" y hacer el código más limpio mediante el uso de caja de conmutación, polimorfismo o incluso un buen ol' if/else. El número de casos juega un papel importante aquí, supongo.

0

Si las cadenas son estáticos, se puede hacer una enumeración. y enciéndalo.

1

puedo enviar un caso típico de cómo he sustituido caso conmutador con enumeración.

antes refactor tengo enumeración PatternTypes:

public enum PatternTypes { 

    ALPHA_CHAR, ALPHANUMERIC_CHAR, ADDITIONAL_CHAR, UNICODE_BMP_CHARS 
} 

y función:

private static final String ALPHA_CHAR = "[a-zA-Z]+"; 
    private static final String ALPHANUMERIC_CHAR = "[a-zA-Z0-9\\_]+"; 
    private static final String ADDITIONAL_CHAR = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"; 
    private static final String UNICODE_BMP_CHARS = "[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"; 

/* 
    * Match given classAbbr with given RegEx pattern 
    */ 
    private void checkInvalidClassAbbr(String classAbbr, 
      PatternTypes classAbbrPattern) { 

     switch (classAbbrPattern) { 
     case ALPHA_CHAR: 

      checkUnmatched(classAbbr, ALPHA_CHAR, CLASS_ABBR_VAR_NAME); 
      break; 
     case ALPHANUMERIC_CHAR: 

      checkUnmatched(classAbbr, ALPHANUMERIC_CHAR, CLASS_ABBR_VAR_NAME); 
      break; 
     case ADDITIONAL_CHAR: 
      throw new MalFormedDNException("Not support Pattern Type:" 
        + classAbbrPattern); 

     case UNICODE_BMP_CHARS: 
      throw new MalFormedDNException("Not support Pattern Type:" 
        + classAbbrPattern); 
     } 

    } 

Después de perfeccionar por PatternTypes modificar para:

public enum PatternTypes { 

    /** 
    * RegEx patterns divided by restriction level 
    */ 
    ALPHA_CHAR("[a-zA-Z]+"), 
    ALPHANUMERIC_CHAR("[a-zA-Z0-9\\_]+"), 
    ADDITIONAL_CHAR("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~]+"), 
    UNICODE_BMP_CHARS("[a-zA-Z0-9\\_\\-\\,\\.\\s\\!\\#\\$\\&\\(\\)\\*\\+\\;\\:\\=\\?\\@\\|\\[\\]\\{\\}\\~\u00A0-\uD7FF\uF900-\uFFFD]+"); 

    public String getPatternContent() { 
     return patternContent; 
    } 

    private String patternContent; 

    PatternTypes(String patternContent) { 
     this.patternContent = patternContent; 
    } 
} 

y función simplificar a:

/* 
    * Match given classAbbr with given RegEx pattern 
    */ 
    private void checkInvalidClassAbbr(String classAbbr, PatternTypes classAbbrPattern) { 

      if (PatternTypes.ADDITIONAL_CHAR.equals(classAbbrPattern) || PatternTypes.UNICODE_BMP_CHARS.equals(classAbbrPattern)){ 
       throw new MalFormedDNException("RegEx pattern:" + classAbbrPattern.name() + "is not allowed for Class Abbr"); 
      } 

      checkUnmatched(classAbbr, classAbbrPattern.getPatternContent(), CLASS_ABBR_VAR_NAME); 

    } 
0

Hashmap no se considera compatible con la memoria, por lo que puede utilizar Enum para este fin.

Ejemplo:

class EnumExample4{ 
enum Season{ 
WINTER(5), SPRING(10), SUMMER(15), FALL(20); 

private int value; 
private Season(int value){ 
this.value=value; 
} 
} 
public static void main(String args[]){ 

System.out.println(Season.WINTER.value); //This gives you 5 
}} 

Esto le sve de escribir Interruptor de casos o si las declaraciones.

+2

¿Puede dar alguna referencia para respaldar el reclamo * Hashmap no se considera compatible con la memoria *? Si puede, edite su respuesta para vincularla allí. – derM

Cuestiones relacionadas