Próbuję napisać serwlet, który wykonuje zadania na podstawie wartości „action” przekazanej mu jako dane wejściowe.
Oto próbka tego
public class SampleClass extends HttpServlet {
public static void action1() throws Exception{
//Do some actions
}
public static void action2() throws Exception{
//Do some actions
}
//And goes on till action9
public void doPost(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException {
String action = req.getParameter("action");
/**
* I find it difficult in the following ways
* 1. Too lengthy - was not comfortable to read
* 2. Makes me fear that action1 would run quicker as it was in the top
* and action9 would run with a bit delay - as it would cross check with all the above if & else if conditions
*/
if("action1".equals(action)) {
//do some 10 lines of action
} else if("action2".equals(action)) {
//do some action
} else if("action3".equals(action)) {
//do some action
} else if("action4".equals(action)) {
//do some action
} else if("action5".equals(action)) {
//do some action
} else if("action6".equals(action)) {
//do some action
} else if("action7".equals(action)) {
//do some action
} else if("action8".equals(action)) {
//do some action
} else if("action9".equals(action)) {
//do some action
}
/**
* So, the next approach i tried it with switch
* 1. Added each action as method and called those methods from the swith case statements
*/
switch(action) {
case "action1": action1();
break;
case "action2": action2();
break;
case "action3": action3();
break;
case "action4": action4();
break;
case "action5": action5();
break;
case "action6": action6();
break;
case "action7": action7();
break;
case "action8": action8();
break;
case "action9": action9();
break;
default:
break;
}
/**
* Still was not comfortable since i am doing un-necessary checks in one way or the other
* So tried with [reflection][1] by invoking the action methods
*/
Map<String, Method> methodMap = new HashMap<String, Method>();
methodMap.put("action1", SampleClass.class.getMethod("action1"));
methodMap.put("action2", SampleClass.class.getMethod("action2"));
methodMap.get(action).invoke(null);
/**
* But i am afraid of the following things while using reflection
* 1. One is Security (Could any variable or methods despite its access specifier) - is reflection advised to use here?
* 2. Reflection takes too much time than simple if else
*/
}
}
Wszystko, czego potrzebuję, to uciec od zbyt wielu sprawdzeń w moim kodzie w celu poprawienia czytelności i zachowania kodu. Więc wypróbowałem inne alternatywy, takie jak
1. zmień skrzynkę - nadal wykonuje zbyt wiele kontroli przed wykonaniem mojej czynności
2. odbicie
i] jedną z najważniejszych rzeczy jest bezpieczeństwo - które pozwala mi na dostęp nawet do zmiennych i metod w klasie pomimo jej specyfikatora dostępu - nie jestem pewien, czy mógłbym użyć jej w kodzie
ii] a drugim jest to, że zajmuje to więcej czasu niż zwykłe kontrole if / else-if
Czy jest jakieś lepsze podejście lub lepszy projekt, który ktoś mógłby zaproponować, aby lepiej zorganizować powyższy kod?
EDYTOWANE
Dodałem odpowiedź na powyższy fragment, biorąc pod uwagę poniższą odpowiedź .
Ale nadal następujące klasy „ExecutorA” i „ExecutorB” wykonują tylko kilka wierszy kodu. Czy dobrą praktyką jest dodawanie ich jako klasy niż dodawanie ich jako metody? Proszę doradzić w tym zakresie.
źródło
Odpowiedzi:
W oparciu o poprzednią odpowiedź Java pozwala, aby wyliczenia miały właściwości, dzięki czemu można zdefiniować wzorzec strategii, coś w rodzaju
Wtedy twoja
Executor
(strategia) byłabyI wszystkie twoje
doPost
metody if / else stają się czymś podobnymW ten sposób możesz nawet użyć lambdów dla wykonawców w wyliczeniach.
źródło
Executor
jest (lub może być) funkcjonalnym interfejsem.Zamiast używać refleksji, użyj dedykowanego interfejsu.
tj. zamiast:
Posługiwać się
Implementuje każdą z nich dla każdej akcji, a następnie:
Oczywiście to rozwiązanie nie jest najlżejsze, więc może nie będziesz musiał podchodzić do tej długości.
źródło
ProcessAction
zamiast CzyActionProcess
to tak ...?Użyj wzorca poleceń , będzie to wymagało interfejsu poleceń podobnego do tego:
Jeśli
Actions
są lekkie i tanie w budowie, użyj metody fabrycznej. Załaduj nazwy klas z pliku właściwości, który mapujeactionName=className
i użyj prostej metody fabrycznej, aby zbudować akcje do wykonania.Jeśli działania są drogie w budowie, użyj puli, takiej jak HashMap ; jednakże w większości przypadków sugerowałbym, że można tego uniknąć zgodnie z zasadą pojedynczej odpowiedzialności, delegując kosztowny element do pewnej wstępnie zbudowanej wspólnej puli zasobów zamiast samych poleceń.
Można je następnie wykonać za pomocą
Jest to bardzo solidne i oddzielone podejście, które stosuje SRP, LSP i ISP zasad SOLID . Nowe polecenia nie zmieniają kodu mapującego polecenia. Polecenia są łatwe do wdrożenia. Można je po prostu dodać do projektu i pliku właściwości. Polecenia powinny zostać ponownie wprowadzone, co czyni go bardzo wydajnym.
źródło
Można użyć obiektu opartego na wyliczaniu, aby zmniejszyć konieczność twardego kodowania wartości ciągu. Zaoszczędzi ci to trochę czasu i sprawi, że kod będzie bardzo fajny do czytania i rozszerzania w przyszłości.
źródło
Wzorzec metody fabrycznej jest tym, co wyglądam, jeśli szukasz skalowalnego i mniej konserwowalnego projektu.
Wzorzec metody fabrycznej definiuje interfejs do tworzenia obiektu, ale pozwól, aby podklasa zdecydowała, którą klasę utworzyć. Metoda fabryczna pozwala klasie odroczyć tworzenie instancji do podklasy.
action1, action2 ........ actionN konkretna implementacja za pomocą metody doStuff Implementacja rzeczy do zrobienia.
Zadzwoń
Więc w przyszłości, jeśli zostaną wprowadzone dalsze działania, wystarczy dodać konkretną klasę.
źródło
W odniesieniu do @J. Odpowiedź Pichardo Piszę modyfikację powyższego fragmentu w następujący sposób
źródło