Es tut mir leid, dass ich keine Frage finden kann, die diese Frage beantwortet. Ich bin mir fast sicher, dass jemand anderes sie zuvor gestellt hat.
Mein Problem ist, dass ich einige Systembibliotheken schreibe, um eingebettete Geräte auszuführen. Ich habe Befehle, die über Radiosendungen an diese Geräte gesendet werden können. Dies kann nur per Text erfolgen. Innerhalb der Systembibliotheken habe ich einen Thread, der die Befehle behandelt, die so aussehen
if (value.equals("A")) { doCommandA() }
else if (value.equals("B")) { doCommandB() }
else if etc.
Das Problem ist, dass es viele Befehle gibt, die schnell zu etwas außer Kontrolle geraten. Es ist schrecklich, herauszuschauen, schmerzhaft zu debuggen und in ein paar Monaten umwerfend zu verstehen.
Antworten:
Verwenden des Befehlsmusters :
Erstellen Sie dann ein
Map<String,Command>
Objekt und füllen Sie es mitCommand
Instanzen:dann können Sie Ihre if / else if- Kette ersetzen durch:
BEARBEITEN
Sie können auch spezielle Befehle wie
UnknownCommand
oder hinzufügenNullCommand
, benötigen jedoch einenCommandMap
Befehl, der diese Eckfälle behandelt, um die Überprüfungen des Clients zu minimieren.quelle
Mein Vorschlag wäre eine Art leichte Kombination aus Aufzählung und Befehlsobjekt. Dies ist eine von Joshua Bloch in Punkt 30 von Effective Java empfohlene Redewendung.
Natürlich können Sie Parameter an doCommand übergeben oder Rückgabetypen haben.
Diese Lösung ist möglicherweise nicht wirklich geeignet, wenn die Implementierungen von doCommand nicht wirklich zum Aufzählungstyp "passen", was - wie üblich, wenn Sie einen Kompromiss eingehen müssen - etwas unscharf ist.
quelle
Haben Sie eine Aufzählung von Befehlen:
Wenn Sie mehr als ein paar Befehle haben, prüfen Sie die Verwendung des Befehlsmusters, wie an anderer Stelle beantwortet (obwohl Sie die Aufzählung beibehalten und den Aufruf der implementierenden Klasse in die Aufzählung einbetten können, anstatt eine HashMap zu verwenden). Ein Beispiel finden Sie in der Antwort von Andreas oder jens auf diese Frage.
quelle
Die Implementierung einer Schnittstelle, wie sie von dfa einfach und klar demonstriert wird, ist sauber und elegant (und "offiziell" unterstützt). Dafür ist das Schnittstellenkonzept gedacht.
In C # könnten wir Delegaten für Programmierer verwenden, die gerne Funktionszeiger in c verwenden, aber die DFA-Technik ist die Art zu verwenden.
Sie könnten auch ein Array haben
Dann könnten Sie einen Befehl per Index ausführen
Plagiieren von DFAs, aber mit einer abstrakten Basisklasse anstelle einer Schnittstelle. Beachten Sie den cmdKey, der später verwendet wird. Aus Erfahrung stelle ich fest, dass ein Gerätebefehl häufig auch Unterbefehle enthält.
Konstruieren Sie Ihre Befehle so:
Sie können dann die generische HashMap oder HashTable erweitern, indem Sie eine Schlüssel-Wert-Paar-Saugfunktion bereitstellen:
Erstellen Sie dann Ihren Befehlsspeicher:
Jetzt können Sie Steuerelemente objektiv senden
quelle
Nun, ich schlage vor, Befehlsobjekte zu erstellen und sie mit dem String als Schlüssel in eine Hashmap einzufügen.
quelle
Auch wenn ich glaube, dass der Befehlsmusteransatz eher auf die besten Praktiken ausgerichtet ist und auf lange Sicht gewartet werden kann, ist hier eine Einzeiler-Option für Sie:
org.apache.commons.beanutils.MethodUtils.invokeMethod (this, "doCommand" + value, null);
quelle
Normalerweise versuche ich es so zu lösen:
Das hat viele Vorteile:
1) Es ist nicht möglich, eine Aufzählung hinzuzufügen, ohne exec zu implementieren. Sie werden also kein A verpassen.
2) Sie müssen es nicht einmal zu einer Befehlskarte hinzufügen, also keinen Boilerplate-Code zum Erstellen der Karte. nur die abstrakte Methode und ihre Implementierungen. (Das ist wohl auch Boilerplate, aber es wird nicht kürzer ..)
3) Sie sparen alle verschwendeten CPU-Zyklen, indem Sie eine lange Liste von ifs durchgehen oder hashCodes berechnen und nachschlagen.
Bearbeiten: Wenn Sie keine Aufzählungen, sondern Zeichenfolgen als Quelle haben,
Command.valueOf(mystr).exec()
rufen Sie einfach die exec-Methode auf. Beachten Sie, dass Sie den öffentlichen Modifikator für execif verwenden müssen, den Sie von einem anderen Paket aus aufrufen möchten.quelle
Am besten verwenden Sie eine Befehlskarte.
Aber haben Sie eine Reihe von Karten, mit denen Sie fertig werden müssen? Am Ende klopfen viele Karten herum. Dann lohnt es sich, es mit Enums zu machen.
Sie können dies mit einer Aufzählung tun, ohne Schalter zu verwenden (wahrscheinlich benötigen Sie die Getter im Beispiel nicht), wenn Sie der Aufzählung eine Methode hinzufügen, um nach "Wert" aufzulösen. Dann können Sie einfach tun:
Update: Statische Zuordnung hinzugefügt, um Iterationen bei jedem Aufruf zu vermeiden. Schamlos von dieser Antwort gekniffen .
quelle
Die Antwort von @dfa ist meiner Meinung nach die beste Lösung.
Ich stelle nur einige Schnipsel zur Verfügung, falls Sie Java 8 verwenden und Lambdas verwenden möchten!
Befehl ohne Parameter:
(Sie könnten ein Runnable anstelle von Command verwenden, aber ich halte es nicht für semantisch richtig):
Befehl mit einem Parameter:
Wenn Sie einen Parameter erwarten, können Sie Folgendes verwenden
java.util.function.Consumer
:Im obigen Beispiel
doSomethingX
ist eine Methode inmyObj
der Klasse vorhanden, die ein beliebiges Objekt (param
in diesem Beispiel benannt) als Argument verwendet.quelle
Wenn Sie mehrere imbrizierte 'if'-Anweisungen haben, ist dies ein Muster für die Verwendung einer Regelengine . Siehe zum Beispiel JBOSS Drools .
quelle
Verwenden Sie einfach eine HashMap, wie hier beschrieben:
quelle
Wenn es möglich wäre, eine Reihe von Prozeduren (was Sie Befehle nannten) zu haben, wäre das nützlich.
Sie könnten jedoch ein Programm schreiben, um Ihren Code zu schreiben. Es ist alles sehr systematisch, wenn (value = 'A') commandA (); sonst wenn (........................ etc.
quelle
Ich bin mir nicht sicher, ob sich das Verhalten Ihrer verschiedenen Befehle überschneidet, aber Sie sollten sich auch das Muster der Verantwortungskette ansehen , das mehr Flexibilität bietet, indem mehrere Befehle einige Eingabewerte verarbeiten können.
quelle
Befehlsmuster ist der richtige Weg. Hier ist ein Beispiel mit Java 8:
1. Definieren Sie die Schnittstelle:
2. Implementieren Sie die Schnittstelle mit jeder der Erweiterungen:
und
und so weiter .....
3. Definieren Sie den Client:
4. Und das ist das Beispielergebnis:
quelle
Wenn es viele Dinge tut, dann wird es viel Code geben, davon kann man nicht wirklich wegkommen. Machen Sie es einfach, zu folgen, geben Sie den Variablen sehr aussagekräftige Namen, Kommentare können auch helfen ...
quelle