2013-04-26 17 views
6

Posiadam klasę użytkową, która wykonuje pewną pracę. Oczywiście jest on zamknięty dla rozszerzenia i wszystkie metody są statyczne. Dla uproszczenia, klasy wygląda następująco:Metoda szablonowa dla klas statycznych

public final class Util { 
    private Util() { } 

    public static void doWork() { 
     // some work 
     int variable = help(); 
     // some work uses variable 
    } 

    private static int help() { 
     // some helper functionality 
    } 
} 

klasa ma metodę doWork który wykonuje wiele obliczeń. Nawiasem mówiąc, metoda wywołuje metodę pomocniczą help, aby uzyskać wynik, a reszta kodu korzysta z wyniku zwróconego przez metodę help.

Teraz w kodzie klienta chcę ponownie użyć funkcji metody doWork, ale zamiast wywoływania help chcę wywołać metodę help2. Najprostszym rozwiązaniem jest po prostu utworzenie metody doWork2 z zastępowaniem help na help2.

Jest to bardzo złe podejście, ponieważ każda zmiana w doWork musi być również replikowana w doWork2. Jest to bardzo podobne do wzoru Template Method, ale z tego powodu, że nie mamy tu rozszerzenia, nie możemy go zastosować.

Najlepsze rozwiązanie wymyśliłem, aby dodać parametr do tej metody, ale zachować wszystkie istniejące użytkownikom doWork:

public static void doWork() { 
    doWorkWithParameter(true); 
} 

public static void doWorkWithParameter(boolean helpOrHelp2) { 
    // some work 
    int variable = helpOrHelp2 ? help() : help2(); 
    // some work uses variable 
} 

Jakie są lepsze rozwiązania projektowe mogą być stosowane, aby rozwiązać ten problem? Czy istnieje sposób na osiągnięcie elastyczności, takiej jak Template Pattern, ale w aplikacji do wykorzystania klas.

Z góry dziękuję.

+0

Czy istnieje jakikolwiek powód, aby nie używać przeciążenie metody w roztworze? 'public static void doWork() {...}' 'public static void doWork (boolean param) {...}' – Crazenezz

+0

Albo jeszcze lepiej 'public static void doWork (int variable)'. Chociaż podejrzewam, że rzeczywista odpowiedź jest taka, że ​​pomyłki wynikają ze statyki i że obiekty dostarczają czystszą odpowiedź - trudną do określenia przy pomocy abstrakcyjnych przykładów. –

+0

To, czego szukasz, to wzór strategii. Sprawdź odpowiedź Arnalda. –

Odpowiedz

5

Moja propozycja jest inspirowana w Command Pattern, gdzie klasa Util jest Invoker i każdy DoWork-help pary są obudowane za pomocą interfejsu pracownika.

Pracownik inteface mogłyby być pewne jak

public interface Worker { 
    public void doWork(); 
    public int help(); 
} 

utylizacji o Klasa

public final class Util { 
    private Util() { } 

    public static void toWork(Worker worker){ 
     worker.doWork(); 
    } 

} 

Pracownik betonu (implementacje pomoc i DoWork)

public class ConcreteWorker implements Worker{ 

    @Override 
    public void doWork() { 
     // TODO Auto-generated method stub 
      int variable = help(); 

    } 

    @Override 
    public int help() { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

} 

inny pracownik

public class ConcreteWorker2 implements Worker{ 

    @Override 
    public void doWork() { 
     // TODO Auto-generated method stub 
      int variable = help(); 

    } 

    @Override 
    public int help() { 
     // TODO Auto-generated method stub 
     return 1; 
    } 

} 

a wykonanie

Util.toWork(new ConcreteWorker()); 
Util.toWork(new ConcreteWorker2()); 
+0

Zamiast interfejsu Robotnika lepiej uczynić go klasą abstrakcyjną za pomocą metody doWork(). Jest to dokładnie to samo, co sugeruję, ale po prostu z większym kodem. Masz cztery klasy zamiast jednego. Przypuszczam, że przeliczniki są lepszym zamiennikiem metod statycznych. – Mikhail

+1

Świetnie! Wygląda jak wzorzec strategii 'Collections.sort (lst, Comparator)'. Jak mogłem tęsknić? – mishadoff

1

Można by utworzyć 2 statyczny obiekt Help1 & Help2 realizacji Help interfejsu Wich mieć metodę help() i zmienić metodę doWorkWithParameter tak:

public static void doWorkWithParameter(Help h) { 
    int variable = h.help(); 
} 

Jest ściśle związana z bieżącym rozwiązania. Ale myślę, że to trochę bardziej "zorientowane na obiekt".

1

Nie tak dawno temu zrobiłem tak:

public static enum Helper{ 
    OLD(){ 
     public int help(){ 
      return 0; 
     } 
    }, 

    NEW(){ 
     public int help(){ 
      return 1; 
     } 
    }; 

    public abstract int help(); 

    public void doWork() { 
     int variable = help(); 
    } 
} 

public static Helper HELPER = Helper.NEW; 

wtedy możemy nazwać:

Constants.HELPER.doWork() 

Przełączając pomocnik wartości stałych mogę zmienić zachowanie. czy można zrobić:

Helper.OLD.doWork(); 
Helper.NEW.doWork(); 
+0

Dzięki, niezła sztuczka. – mishadoff

+0

To pochodzi z efektywnej książki Java - "Artykuł 34: Emuluj rozszerzalne wyliczenia z interfejsami" – Mikhail

Powiązane problemy