Mam klasę używaną do przetwarzania płatności od klientów. Wszystkie metody tej klasy oprócz jednej są takie same dla każdego klienta, z wyjątkiem jednej, która oblicza (na przykład), ile jest winien użytkownik klienta. Może się to znacznie różnić w zależności od klienta i nie ma łatwego sposobu na uchwycenie logiki obliczeń w pliku właściwości, ponieważ może istnieć dowolna liczba czynników niestandardowych.
Mógłbym napisać brzydki kod, który przełącza się na podstawie ID klienta:
switch(customerID) {
case 101:
.. do calculations for customer 101
case 102:
.. do calculations for customer 102
case 103:
.. do calculations for customer 103
etc
}
ale wymaga to przebudowania klasy za każdym razem, gdy pozyskujemy nowego klienta. Jaki jest lepszy sposób?
[Edytuj] „Duplikat” artykułu jest zupełnie inny. Nie pytam, jak uniknąć instrukcji switch, proszę o nowoczesny projekt, który najlepiej pasuje do tego przypadku - który mógłbym rozwiązać za pomocą instrukcji switch, gdybym chciał napisać kod dinozaura. Podane tam przykłady są ogólne i nie są pomocne, ponieważ w zasadzie mówią „Hej, przełącznik działa całkiem dobrze w niektórych przypadkach, a nie w innych”.
[Edytuj] Zdecydowałem się na najwyższą odpowiedź (utwórz osobną klasę „Klient” dla każdego klienta, który implementuje standardowy interfejs) z następujących powodów:
Spójność: mogę utworzyć interfejs, który zapewnia, że wszystkie klasy klientów odbierają i zwracają takie same dane wyjściowe, nawet jeśli zostały utworzone przez innego programistę
Utrzymywalność: Cały kod jest napisany w tym samym języku (Java), więc nie ma potrzeby, aby ktokolwiek uczył się oddzielnego języka kodowania, aby zachować coś, co powinno być śmiertelnie proste.
Ponowne użycie: w przypadku pojawienia się podobnego problemu w kodzie, mogę ponownie użyć klasy Customer do przechowywania dowolnej liczby metod implementacji „niestandardowej” logiki.
Znajomość: już wiem, jak to zrobić, więc mogę to zrobić szybko i przejść do innych, bardziej palących problemów.
Wady:
Każdy nowy klient wymaga kompilacji nowej klasy Customer, co może nieco komplikować sposób, w jaki kompilujemy i wdrażamy zmiany.
Każdy nowy klient musi zostać dodany przez programistę - osoba obsługująca nie może po prostu dodać logiki do czegoś takiego jak plik właściwości. Nie jest to idealne ... ale wtedy nie byłem również pewien, w jaki sposób osoba z działu pomocy technicznej byłaby w stanie napisać niezbędną logikę biznesową, szczególnie jeśli jest ona złożona z wieloma wyjątkami (co jest prawdopodobne).
Nie będzie dobrze skalować, jeśli dodamy wielu nowych klientów. Nie jest to oczekiwane, ale jeśli tak się stanie, będziemy musieli przemyśleć wiele innych części kodu, jak również ten.
Dla zainteresowanych możesz użyć Java Reflection, aby wywołać klasę według nazwy:
Payment payment = getPaymentFromSomewhere();
try {
String nameOfCustomClass = propertiesFile.get("customClassName");
Class<?> cpp = Class.forName(nameOfCustomClass);
CustomPaymentProcess pp = (CustomPaymentProcess) cpp.newInstance();
payment = pp.processPayment(payment);
} catch (Exception e) {
//handle the various exceptions
}
doSomethingElseWithThePayment(payment);