2015-01-20 15 views
20

Mam instrukcję if else, która może wzrosnąć w najbliższej przyszłości.Zamienianie instrukcji else w wzór

public void decide(String someCondition){ 

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

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

      // 
      someMethod("anotherParameter"); 

     } 
     . 
     . 
     else{ 

      someMethod("elseParameter"); 

     } 
} 

Ponieważ to już wygląda nieprzyjemnie, myślę, że byłoby lepiej, gdybym mógł zastosować tutaj dowolne wzorce projektowe. Przyjrzałem się wzorcowi strategii, ale nie jestem pewien, czy to zmniejszy, jeśli w innym przypadku stan. Jakieś sugestie?

+1

pójdę do jakiegoś prostego tabeli decyzyjnej –

+2

nie uzyskać notacji : czy "conditionOne" jest ciągiem? –

+0

Strategia jest przeznaczona do zastępowalnych algorytmów. W twoim przypadku spójrz na wzór polecenia. Jeśli uważasz, że to jest warte wysiłku. – AlexWien

Odpowiedz

24

To jest klasyczny Replace Condition dispatcher with Command w książce Refactoring to Patterns.

enter image description here

Zasadniczo dokonać Command obiektu dla każdego z bloków kodu w starego if/grupa indziej, a następnie zrobić mapę tych poleceń, gdzie klawisze są struny stan

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

Wtedy zamiast swojego iF/kodu innego to zamiast:

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

teraz, jeśli chcesz później dodać nowe polecenia, ty po prostu dodaj do skrótu.

Jeśli chcesz obsłużyć domyślny przypadek, możesz użyć wzoru Null Object, aby obsłużyć przypadek, w którym warunek nie znajduje się na mapie.

Handler defaultHandler = ... 

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

Będę z szacunkiem nie zgadzać się z używaniem polecenia, chyba że musisz wykonać/cofnąć/ponowić lub zapisać alternatywy jako obiekty. Intencja dla Command (z referencji GoF): "Enkapsuluj żądanie jako obiekt, umożliwiając w ten sposób parametryzowanie klientów za pomocą różnych żądań, kolejki lub dzienników i obsługujących operacje, które można cofnąć." – Fuhrmanator

+0

@Fuhrmanator, w jaki sposób to nie "Encapsula [ting] żądanie jako obiekt umożliwiający sparametryzowanie klientów z różnymi żądaniami"? Powinieneś przeczytać książkę * Refactoring to Patterns *, gdzie technika ta ma cały rozdział poświęcony jej. – dkatzel

+0

Ma sens enkapsulacja "partii kodu", aby obiekty (Command) stały się parametrem dla klienta. Ale problem z OP jest pojedynczym wywołaniem metody w każdym, jeśli zmienia się tylko poprzez argument. Jego komentarz: "Metoda jest zawsze taka sama, argumenty różnią się." – Fuhrmanator

1

Chyba trzeba mieć już uznane, ale jeśli używasz JDK 7 lub powyżej, można przełączyć na sznurkach. W ten sposób twój kod może wyglądać czystsze niż kilka instrukcji if-else.

10

Ogólna rekomendacja Martina Fowlera to Replace Conditional with Polymorphism.

Pod względem wzorców projektowych często był to wzór strategii Replace Conditional Logic with Strategy.

Jeśli masz mały, skończony zbiór warunków, polecam użyć enum do realizacji strategii Wzorzec (dostarczenie metody abstrakcyjne w enum i zastąpić go dla każdego stała).

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

} 

Jeśli to naprawdę tylko parametr chcesz wybrać, a następnie można zdefiniować enum tak zamiast:

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

}