2015-01-20 23 views
20

Ho una dichiarazione if else che potrebbe crescere nel prossimo futuro.Sostituire if else statement with pattern

public void decide(String someCondition){ 

     if(someCondition.equals("conditionOne")){ 
      // 
      someMethod("someParameter"); 

     }else if(someCondition.equals("conditionTwo")){ 

      // 
      someMethod("anotherParameter"); 

     } 
     . 
     . 
     else{ 

      someMethod("elseParameter"); 

     } 
} 

Dato, questo sta già cercando disordinato, penso che sarebbe meglio se posso applicare eventuali modelli di progettazione qui. Ho esaminato il modello di strategia, ma non sono sicuro che questo ridurrà le altre condizioni qui. Eventuali suggerimenti?

+1

vorrei andare per qualche semplice tabella di decisione –

+2

Non capisco la tua notazione : è 'conditionOne' a String? –

+0

La strategia è per algoritmi sostituibili. Nel tuo caso guarda lo schema di comando. Se pensi che valga la pena. – AlexWien

risposta

24

Questo è un classico Replace Condition dispatcher with Command nel libro Refactoring to Patterns.

enter image description here

Fondamentalmente si fanno un oggetto Command per ciascuno dei blocchi di codice nel tuo vecchio se/gruppo altro e poi fare una mappa di questi comandi dove le chiavi sono i tuoi condizione Strings

interface Handler{ 
    void handle(myObject o); 
} 


Map<String, Handler> commandMap = new HashMap<>(); 
//feel free to factor these out to their own class or 
//if using Java 8 use the new Lambda syntax 
commandMap.put("conditionOne", new Handler(){ 
     void handle(MyObject o){ 
       //get desired parameters from MyObject and do stuff 
      } 
}); 
... 

Poi al posto del tuo se il codice/altra cosa è invece:

commandMap.get(someCondition).handle(this); 

Ora, se è necessario aggiungere successivamente nuovi comandi, è basta aggiungere all'hash.

Se si desidera gestire un caso predefinito, è possibile utilizzare il modello Null Object per gestire il caso in cui una condizione non è presente nella mappa.

Handler defaultHandler = ... 

if(commandMap.containsKey(someCondition)){ 
    commandMap.get(someCondition).handle(this); 
}else{ 
    defaultHandler.handle(this); 
} 
+2

Non rispetterò rispettosamente l'uso del comando, a meno che non sia necessario eseguire/annullare/ripristinare o memorizzare alternative come oggetti. L'intento del comando (dal riferimento GoF): "Incapsula una richiesta come oggetto, consentendo così di parametrizzare i client con richieste diverse, accodare o registrare richieste e supportare operazioni annullabili." – Fuhrmanator

+0

@Fuhrmanator come non è "Encapsula [ting] una richiesta come oggetto che consente di parametrizzare i client con richieste diverse"? Dovresti leggere il libro * Refactoring to Patterns * dove questa tecnica ha un intero capitolo dedicato ad esso – dkatzel

+0

Ha senso incapsulare "molti codici" in modo che gli oggetti (Command) diventino il parametro per il client. Ma il problema degli OP è una chiamata al singolo metodo in ognuno se, che cambia solo per argomento. Il suo commento: "Il metodo è sempre lo stesso, gli argomenti sono diversi." – Fuhrmanator

1

Credo che si deve aver già preso in considerazione, ma se si utilizza JDK 7 o superiore, è possibile passare sulle stringhe. In questo modo il tuo codice può sembrare più pulito di una serie di istruzioni if-else.

10

La raccomandazione generale di Martin Fowler è Replace Conditional with Polymorphism.

In termini di motivi di progettazione questo spesso è il modello di strategia Replace Conditional Logic with Strategy.

Se si dispone di una piccola , insieme finito di condizioni, vi consiglio di utilizzare un enum per l'attuazione del modello di strategia (di fornire un metodo astratto nella enum e sovrascrivere per ogni costante).

public enum SomeCondition{ 
    CONDITION_ONE{ 

     public void someMethod(MyClass myClass){ 
       //... 
     } 
    }, 

    CONDITION_TWO{ 

     public void someMethod(MyClass myClass){ 
     } 

    } 

    public abstract void someMethod(MyClass myClass); 

} 

public class MyClass{ 
//... 
    public void decide(SomeCondition someCondition){ 
     someCondition.someMethod(this); 
    } 

} 

Se è in realtà solo un parametro da prendere, allora si potrebbe definire l'enum come questo, invece:

public enum SomeCondition{ 
    CONDITION_ONE("parameterOne"), 

    CONDITION_TWO("parameterTwo"); 

    private SomeCondition(String parameter){ 
     this.parameter = parameter; 
    } 

    public String getParameter(){ 
     return parameter; 
    } 

} 


public class MyClass{ 
//... 
    public void decide(SomeCondition someCondition){ 
     someMethod(someCondition.getParameter()); 
    } 

}