Przepraszam, że nie mogę znaleźć odpowiedzi na to pytanie, jestem prawie pewien, że ktoś inny zadał to wcześniej.
Mój problem polega na tym, że piszę biblioteki systemowe do uruchamiania urządzeń wbudowanych. Mam polecenia, które można wysłać do tych urządzeń za pośrednictwem transmisji radiowych. Można to zrobić tylko tekstem. wewnątrz bibliotek systemowych mam wątek obsługujący polecenia, które wyglądają następująco
if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() }
else if etc.
Problem polega na tym, że jest w nim wiele poleceń, które szybko wymkną się spod kontroli. Okropne, aby wyglądać na zewnątrz, bolesne do debugowania i niewyobrażalne, aby zrozumieć za kilka miesięcy.
Odpowiedzi:
przy użyciu wzorca polecenia :
następnie zbuduj
Map<String,Command>
obiekt i zapełnij goCommand
instancjami:wtedy możesz zamienić swój łańcuch if / else if na :
EDYTOWAĆ
możesz także dodać specjalne polecenia, takie jak
UnknownCommand
lubNullCommand
, ale potrzebujesz narzędziaCommandMap
obsługującego te narożne przypadki, aby zminimalizować kontrole klienta.źródło
Moją sugestią byłoby lekkie połączenie obiektu wyliczenia i polecenia. To idiom polecany przez Joshuę Blocha w 30 pozycji Effective Java.
Oczywiście możesz przekazać parametry do doCommand lub zwrócić typy.
To rozwiązanie może nie być odpowiednie, jeśli implementacje doCommand tak naprawdę nie „pasują” do typu wyliczenia, co jest - jak zwykle, gdy trzeba dokonać kompromisu - nieco niewyraźne.
źródło
Miej wyliczenie poleceń:
Jeśli masz więcej niż kilka poleceń, spójrz na użycie wzorca Command, zgodnie z odpowiedzią w innym miejscu (chociaż możesz zachować wyliczenie i osadzić wywołanie klasy implementującej w wyliczeniu, zamiast używać HashMap). Zobacz przykładową odpowiedź Andreasa lub Jensa na to pytanie.
źródło
Implementacja interfejsu, jak w prosty i przejrzysty sposób zademonstrowała dfa, jest przejrzysta i elegancka (oraz "oficjalnie" obsługiwana). Właśnie do tego służy koncepcja interfejsu.
W C # moglibyśmy użyć delegatów dla programistów, którzy lubią używać wskaźników funkcji w c, ale metoda DFA jest sposobem na użycie.
Możesz też mieć tablicę
Następnie możesz wykonać polecenie według indeksu
Plagiat z DFA, ale posiadający abstrakcyjną klasę bazową zamiast interfejsu. Zwróć uwagę na cmdKey, który będzie używany później. Z doświadczenia wiem, że często polecenie sprzętowe ma również podkomendy.
Skonstruuj swoje polecenia w ten sposób,
Następnie możesz rozszerzyć ogólny HashMap lub HashTable, udostępniając funkcję zasysania pary klucz-wartość:
Następnie stwórz swój magazyn poleceń:
Teraz możesz obiektywnie przesyłać kontrolki
źródło
Cóż, proponuję utworzyć obiekty poleceń i umieścić je w tablicy mieszającej, używając ciągu jako klucza.
źródło
Nawet jeśli uważam, że podejście wzorcowe jest bardziej ukierunkowane na najlepsze praktyki i możliwe do utrzymania w dłuższej perspektywie, oto jedna opcja dla Ciebie:
org.apache.commons.beanutils.MethodUtils.invokeMethod (this, "doCommand" + wartość, null);
źródło
zazwyczaj staram się to rozwiązać w ten sposób:
ma to wiele zalet:
1) nie można dodać wyliczenia bez zaimplementowania exec. więc nie przegapisz A.
2) nie będziesz musiał nawet dodawać go do żadnej mapy poleceń, więc nie ma standardowego kodu do budowy mapy. tylko abstrakcyjna metoda i jej implementacje. (co jest zapewne również standardowym, ale nie będzie krótsze ..)
3) zaoszczędzisz wszystkie zmarnowane cykle procesora, przeglądając długą listę if lub obliczając hashCodes i wykonując wyszukiwania.
edycja: jeśli nie masz wyliczeń, ale ciągi znaków jako źródło, po prostu użyj
Command.valueOf(mystr).exec()
do wywołania metody exec. Zauważ, że musisz użyć modyfikatora public na execif, który chcesz wywołać z innego pakietu.źródło
Prawdopodobnie najlepiej będzie, jeśli użyjesz mapy poleceń.
Ale czy masz ich zestaw, aby sobie poradzić, skończysz z mnóstwem map. W takim razie warto przyjrzeć się temu, jak zrobić to z Enumami.
Możesz to zrobić za pomocą Enum bez używania przełączników (prawdopodobnie nie potrzebujesz metod pobierających w przykładzie), jeśli dodasz metodę do Enum w celu rozwiązania dla „value”. Następnie możesz po prostu zrobić:
Aktualizacja: dodano mapę statyczną, aby uniknąć iteracji przy każdym wywołaniu. Bezwstydnie uszczypnął tę odpowiedź .
źródło
Odpowiedź udzielona przez @dfa jest moim zdaniem najlepszym rozwiązaniem.
Podam tylko kilka fragmentów na wypadek, gdybyś korzystał z Java 8 i chciał używać Lambdas!
Polecenie bez parametrów:
(możesz użyć Runnable zamiast Command, ale nie uważam tego za poprawne semantycznie):
Polecenie z jednym parametrem:
Jeśli spodziewasz się parametru, którego możesz użyć
java.util.function.Consumer
:W powyższym przykładzie
doSomethingX
jest to metoda obecna wmyObj
klasie 's, która przyjmuje dowolny obiekt (nazwanyparam
w tym przykładzie) jako argument.źródło
jeśli masz wiele wbudowanych instrukcji „if”, jest to wzorzec do korzystania z silnika reguł . Zobacz na przykład JBOSS Drools .
źródło
Po prostu użyj HashMap, jak opisano tutaj:
źródło
gdyby można było mieć tablicę procedur (tak zwanych poleceń), które byłyby przydatne.
ale możesz napisać program do pisania kodu. To wszystko jest bardzo systematyczne, jeśli (wartość = 'A') commandA (); inaczej, jeśli (........................ itd
źródło
Nie jestem pewien, czy masz jakiekolwiek nakładanie się zachowań różnych poleceń, ale możesz również rzucić okiem na wzorzec Łańcucha odpowiedzialności , który może zapewnić większą elastyczność, umożliwiając wielu poleceniom obsługę niektórych wartości wejściowych.
źródło
Wzorzec poleceń jest drogą do zrobienia. Oto jeden przykład użycia java 8:
1. Zdefiniuj interfejs:
2. Zaimplementuj interfejs z każdym rozszerzeniem:
i
i tak dalej .....
3. Zdefiniuj klienta:
4. A oto przykładowy wynik:
źródło
Jeśli robi wiele rzeczy, będzie dużo kodu, naprawdę nie można od tego uciec. Po prostu ułatw śledzenie, nadaj zmiennym bardzo znaczące nazwy, komentarze też mogą pomóc ...
źródło