2012-05-02 14 views
24

Ho il seguente codice:Riduzione if-else in Java

void f(String t) 
{ 
    if(t.equals("a")) 
    { 
    someObject.setType(ObjectType.TYPE_A); 
    } 
else if(t.equals("b")) 
    { 
    someObject.setType(ObjectType.TYPE_B); 
    } 

// 50 more similar code 

} 

C'è un modo semplice per riscrivere la condizione else if-in modo da non avere più di tanto il codice?

risposta

50

Si dovrebbe usare qualcosa per eliminare la ripetizione di someObject.setType(ObjectType....)) Se ObjectType è un enum, quindi scrivere un metodo simile a lì valueOf che raggiungere questo obiettivo. Vedi se ti piace questo tipo di soluzione:

void f(String t) { someObject.setType(ObjectType.byName(t)); } 

enum ObjectType { 
    TYPE_A, TYPE_B; 
    public static ObjectType byName(String name) { 
    return valueOf("TYPE_" + name.toUpperCase()); 
    } 
} 
+2

Brillante .. Non conoscevo il metodo 'valueOf' .. grazie .. – Asha

+2

Non selezionare nit, è sufficiente fare attenzione con la gestione delle eccezioni qui; È necessario racchiudere il valore restituito in un blocco try-catch, per gestire scenari immondizia. – questzen

+0

@questzen Beh, certo, questo è solo lo schema di base. A seconda del desiderio, ci sono vari approcci per gestire la spazzatura. Personalmente preferisco di solito l'eccezione grezza (se è davvero un errore passare in spazzatura). Questo ti dà le informazioni di debug più dirette. –

15

Utilizzare uno Map (che dovrà essere compilato) che esegue la mappatura da String a qualsiasi tipo di valore sono i valori ObjectType.TYPE_x.

+0

Sì, questo è quello che stavo pensando anche io. Ma solo il dubbio che avevo era la memoria necessaria per memorizzare quelle stringhe e la ricerca necessaria per ottenere il tipo. Non c'è altro modo? – Asha

+2

@Asha le stringhe nella mappa (perché sono internate) non occuperanno più spazio delle stringhe letterali. Il tempo di ricerca verrà ridotto perché la ricerca della mappa sarà 'O (log n)' invece di 'O (n)'. – Alnitak

+0

@Alnitak L'uso di un 'HashMap' potrebbe anche arrivare a' O (1) '. –

4

Se si può refactoring t in un char, si potrebbe usare switch invece (Java 6):

void f(char t) { 

    switch(t) { 

    case 'a`: 
     someObject.setType(ObjectType.TYPE_A); 
     break; 
    case 'b': 
     someObject.setType(ObjectType.TYPE_B); 
     break; 

    // ... 

    } 

} 

Come Marko ha sottolineato, si potrebbe andare con String anche in Java 7.

Non è molto più breve, ma più elegante. Inoltre, penso che potrebbe essere anche più veloce, poiché switch funziona vicino a O(1) con tabelle di salto (Qualcuno può confermare se questo è vero?), Se un numero di istruzioni if è O(n).

Per implementazioni più complesse di un singolo setType si potrebbe pensare anche all'implementazione di State Pattern.

14

vorrei aggiungere questo come una funzionalità del enum:

public enum ObjectType { 
    TYPE_A("a"), 
    TYPE_B("b"); 

    private String stringType; 

    private ObjectType(String stringType) { 
     this.stringType = stringType; 
    } 

    public String getStringType() { 
     return this.stringType; 
    } 

    public static ObjectType fromStringType(String s) { 
     for (ObjectType type : ObjectType.values()) { 
      if (type.stringType.equals(s)) { 
       return type; 
      } 
     } 
     throw new IllegalArgumentException("No ObjectType with stringType " + s); 
    } 
} 

... 

void f(String t) { 
    someObject.setType(ObjectType.fromStringType(t)); 
} 
+0

Questo è il metodo che uso di solito. È meglio che fare affidamento sui nomi costanti perché è più flessibile e più difficile da rompere. – Malcolm

2

1.You può andare per istruzione Switch se si dispone di serie di condizioni, se più di 3.

2. puoi convertire le tue istruzioni if ​​else in ternary operations

1

Gli altri suggerimenti sono fantastici - enumerazioni e mappe particolarmente intelligenti. Ma il primo refactoring più elementare che affronterei qui è quello di estrarre un metodo per restituire l'enum direttamente e fare in modo che il chiamante non esegua nient'altro che setType al valore di ritorno di quel metodo.

void f(String t) { 
    final ObjectType type = findType(t); 
    if (type != null) 
    someObject.setType(type); 
    } 

ObjectType findType(String t) { 
    if (t.equals("a")) return ObjectType.TYPE_A; 
    if (t.equals("b")) return ObjectType.TYPE_B; 
    // 50 more similar code 
    } 

In alcuni casi questo sarà sufficiente di per sé; in altri il metodo findType() può portare a una semplice soluzione basata su mappa o su enum.