Gibt es irgendwelche design-Muster zu vermeiden, die eine verschachtelte switch case?
Ich habe ähnliche Art von threads, Aber nicht sicher sind, wie Sie genau anzuwenden, die Lösung zu meinem Fall. Mein problem ist, dass ich eine Reihe von usecases können sagen, 'A','B','C',gibt Es bestimmte Befehle, die ich ausführen müssen, wenn der übergebene Eingabe(2 usecases sind die input) 2 von den aufgeführten usecases. zum Beispiel:
switch(input1)
{
case A:
break;
case B:
break;
case C:
break;
}
innerhalb der jeden Fall werde ich noch prüfen, auf Eingang 2,
so, der endgültige code Aussehen könnte
switch(input1)
{
case A:
{
switch(input2):
case B:
break;
case c:
break;
}
case B:
{
switch(input2):
case A:
break;
case c:
break;
}
....
}
Ich dachte an eine Karte von (paar -, Befehls -), und entfernen Sie diese switch-Case-Anweisungen, aber es ist eine alternative bessere Lösung oder design-problem, dieses problem zu lösen?
- diese Frage kann hilfreich sein. stackoverflow.com/questions/126409/...
- +1 für Polymorphismus in der verlinkten Antwort.
- Diese "usecases", sind Sie eine Art von Staat? Also deine Klasse ist eine state-Maschine, die seinen Zustand ändert (
input1
) während der Ausführung? - ich habe nicht zu ändern, den Staat mit meiner Klasse auf der Basis der usecases, der Einfachheit halber , ich könnte sagen, dass wir darstellen können, ist der usecases durch einige const-strings.
- Ok, was ich meinte, war: Ist das Verhalten der verschiedenen input2 Werte innerhalb eines use-case (Wert1) mehr eng aneinander gebunden? Wie: Ist es eine gute Idee, um Funktionen implementieren, pro use case zu handhaben, die den Wert
input2
? Und spezifischer: Können Sie sich überlappen? (Für einen bestimmten Wert von " input2, gibt es gleich Implementierungen unter verschiedenen Werte von input1?) - Sie dürfen die Funktionen aufrufen, die in einer switch-Anweisung.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn die Leistung nicht, dass das ein großes Problem, dann eine Karte von Funktionszeigern, könnte das eine Lösung.
Vorausgesetzt, das label
A
,B
,C
... sind kleine integral-Werte von weniger als255
.Setup die Karte zuerst
Verwenden Sie die Karte aufrufen, entsprechende Prozedur für jeden Satz von Eingabe:
Beachten Sie, dass Sie haben, um den setup-dispatcher mit jedem möglichen paar von Eingängen. Auch, wenn das paar
KEY(A,B)
undKEY(B,A)
sind gleiche Fall ist, dann können Sie eine Funktion schreiben, die aufgerufeninvoke
in diesem Fall behandeln, um einen einheitlichen Sprachgebrauch für den rest des Codes.dann verwenden Sie es als:
Hoffe, das hilft.
std::pair<char, char>
als Schlüssel? (Das makro ist nützlich, wenn Sie wollen, wechseln Sie auf die Taste, aber es ist nicht notwendig für eine Karte.)'A', 'B'
würde das gleiche Verhalten wie'B', 'A'
, aber wer weiß. Wenn das der Fall ist, wäre das nicht die einfachste Lösung sein, einfach beide Einträge in die Karte?(A,B)
und(B,A)
Probleme sein könnten : 1) es verdoppelt die Größe der Karte, die 2) ändern könnte Ursache Synchronisation problem, ich.e ändern Sie die Funktion-Zeiger für(A,B)
habe und vergessen habe zu ändern, das gleiche für(B,A)
, dann haben Sie zwei verschiedene Verhalten für(A,B)
und(B,A)
sind, sind Sie nicht mehr dasselbe, und das problem wird schwieriger sein, zu finden.switch
insgesamt.std::map
, es ist sauberer zu verwendenstd::pair<char, char>
als Schlüssel, sondern alsint
.In deinem Fall, wie etwa brechen die beiden Schalter in zwei Funktionen
processInput2
für jeden möglichinput1
. So wird es zum BeispielprocessInput2ForA
,...ForB
etc.Eine Möglichkeit ist das aufsplitten der code in einer Funktion pro verschachtelte Fall, also dein Beispiel würde haben 6 Funktionen:
Dann, setzen Sie Sie in ein array Initialisierung für sehr schnelle (Konstante Zeit-lookup zur Laufzeit:
Zum aufrufen der entsprechenden Funktion schreiben:
Beachten Sie, dass durch die Verwendung der C++11
std::function
Typ, die Funktionen, die nicht zu den klassischen Funktionszeigern; Sie kann auch lambda-Funktionen oder Funktor-Objekte.Sie können auch halten einige Teile leer oder weisen Sie die gleiche Funktion mehrere Male. Wenn Sie sich entscheiden, halten einige Einträge leer (also es sollte nicht alles, was man in so einem Fall), überprüfen Sie die Funktion Objekt vor dem Aufruf:
Konnte man immer etwas zu tun:
Aber ehrlich gesagt, in diesem Fall würde ich den verschachtelten switches einfacher
um zu verstehen, angenommen, dass, dass
switch
ist die richtige AntwortIhr problem ist. Für die Zeicheneingabe, es ist oft, aber es gibt
andere alternativen wie eine
std::map<std::pair<char, char>,
, woAction const*>
Action
ist eine virtuelle Basisklasse, die vonjeder Aktion in der Karte ist eine statische Instanz einer abgeleiteten Klasse.
Dies hat den Vorteil, dass auf jede Aktion eine deutliche Objekt
(was nicht unbedingt ein Vorteil, je nachdem, was Sie in die
Aktionen), und wenn die Karte ist dynamisch aufgefüllt werden (zum Beispiel
im Konstruktor von
Action
), Sie können Aktionen hinzufügen, ohneänderungen am Quellcode des parsers (aber Sie dürfen nicht brauchen
diese Flexibilität).
Den vorgeschlagenen Antworten mit Karte oder Tabelle von Zeigern zu handhaben Funktionen sind ok. Ich sehe aber zwei Nachteile:
1) Ein kleiner Leistungsabfall im Vergleich zu den manuellen verschachtelten switches.
2) Fall-handling-Methoden nicht vollständig selbst-beschreibend. Ich meine, Sie haben zu erwähnen, jeder Griff Methoden zweimal in seiner definition und in dem Ort, wo Sie init der Karte.
Sehe ich zwei alternativen:
1) Source-code-Generierung. Automatisch generiert verschachtelte switches von einigen Art der Darstellung. Naja... es ist eine sehr gute option zum erstellen eines optimalen code, wenn nichts ausmacht das hinzufügen von code-Generierung für eine so kleine Aufgabe.
2) Mit Präprozessor-hacks. Nicht das eleganteste, aber durchaus Interesse Weg, damit es funktioniert.
Zuerst erklären wir X-Makro für unsere enum:
Können wir es verwenden, zu erklären, das enum selbst:
Viele Anstrengungen gemacht werden, um "trick", den Präprozessor zu erweitern ELEMENTE rekursiv. Die Grundidee ist gut beschrieben hier.
Nun deklarieren wir unser Handler als template-Funktion Spezialisierung:
Warum nicht verwenden, wenn branchers?
dies ist eine Art des Schreibens, was du meinst.