Ich habe eine Anwendung, die eine Ganzzahl als Eingabe verwendet und basierend auf der Eingabe statische Methoden verschiedener Klassen aufruft. Jedes Mal, wenn eine neue Nummer hinzugefügt wird, müssen wir einen weiteren Fall hinzufügen und eine andere statische Methode einer anderen Klasse aufrufen. Es gibt jetzt 50 Fälle im Schalter und jedes Mal, wenn ich einen weiteren Fall hinzufügen muss, schaudere ich. Gibt es einen besseren Weg, dies zu tun.
Ich habe nachgedacht und bin auf diese Idee gekommen. Ich benutze das Strategiemuster. Anstatt einen Schalterfall zu haben, habe ich eine Karte von Strategieobjekten, wobei der Schlüssel die Eingabe-Ganzzahl ist. Sobald die Methode aufgerufen wird, sucht sie das Objekt und ruft die generische Methode für das Objekt auf. Auf diese Weise kann ich die Verwendung des Switch-Case-Konstrukts vermeiden.
Was denkst du?
quelle
switch
Fall hinzufügen und eine bereits vorhandene Methode in Ihrem komplexen System aufrufen, oder müssen Sie sowohl die Methode als auch ihren Aufruf erfinden?Antworten:
Ich liebe Polymorphismus. Ich liebe SOLID. Ich liebe reine objektorientierte Programmierung. Ich hasse es, wenn diese einen schlechten Ruf bekommen, weil sie dogmatisch angewendet werden.
Sie haben sich nicht gut dafür ausgesprochen, die Strategie umzugestalten. Das Refactoring hat übrigens einen Namen. Es heißt Bedingt durch Polymorphismus ersetzen .
Ich habe auf c2.com einige relevante Ratschläge für Sie gefunden :
Sie haben einen Schalter mit 50 Fällen und Ihre Alternative besteht darin, 50 Objekte zu produzieren. Oh und 50 Zeilen Objektkonstruktionscode. Dies ist kein Fortschritt. Warum nicht? Da dieses Refactoring nichts dazu beiträgt, die Anzahl von 50 zu verringern. Sie verwenden dieses Refactoring, wenn Sie feststellen, dass Sie eine andere switch-Anweisung für dieselbe Eingabe an einer anderen Stelle erstellen müssen. Dann hilft dieses Refactoring, weil es 100 wieder in 50 verwandelt.
Solange Sie sich auf "den Schalter" beziehen, als wäre er der einzige, den Sie haben, empfehle ich dies nicht. Der einzige Vorteil des Refactorings besteht darin, dass die Wahrscheinlichkeit verringert wird, dass ein Goofball Ihren 50-Fall-Schalter kopiert und einfügt.
Was ich empfehle, ist, diese 50 Fälle genau auf Gemeinsamkeiten zu untersuchen, die herausgerechnet werden können. Ich meine 50? "Ja wirklich?" Bist du sicher, dass du so viele Fälle brauchst? Vielleicht versuchen Sie hier zu viel zu tun.
quelle
Eine Karte mit Strategieobjekten allein, die in einer Funktion Ihres Codes initialisiert wird, in der mehrere Codezeilen aussehen
erfordert, dass Sie und Ihre Kollegen die Funktionen / Strategien, die aufgerufen werden sollen, einheitlicher in separaten Klassen implementieren (da Ihre Strategieobjekte alle dieselbe Schnittstelle implementieren müssen). Ein solcher Code ist oft etwas umfassender als
Sie werden jedoch immer noch nicht von der Last befreit, diese Codedatei zu bearbeiten, wenn eine neue Nummer hinzugefügt werden muss. Die wirklichen Vorteile dieses Ansatzes sind anders:
die Initialisierung der Karte wird nun aus dem Dispatch Code getrennt , die tatsächlich ruft die Funktion auf eine bestimmte Nummer zugeordnet, und dieser ist nicht jene 50 Wiederholungen nicht mehr enthalten, wird es einfach aussehen
myMap[number].DoIt(someParameters)
. Dieser Versandcode muss also nicht bei jedem Eintreffen einer neuen Nummer berührt werden und kann nach dem Open-Closed-Prinzip implementiert werden. Wenn Sie Anforderungen erhalten, bei denen Sie den Versandcode selbst erweitern müssen, müssen Sie nicht mehr 50 Stellen ändern, sondern nur eine.Der Inhalt der Karte wird zur Laufzeit bestimmt (während der Inhalt des Switch-Konstrukts vor der Kompilierungszeit bestimmt wird), sodass Sie die Initialisierungslogik flexibler oder erweiterbarer gestalten können.
Ja, es gibt einige Vorteile, und dies ist sicherlich ein Schritt in Richtung mehr SOLID-Code. Wenn sich die Umgestaltung jedoch auszahlt, müssen Sie oder Ihr Team selbst entscheiden. Wenn Sie nicht erwarten, dass der Versandcode geändert wird, die Initialisierungslogik geändert wird und die Lesbarkeit von
switch
kein echtes Problem darstellt, ist Ihr Refactoring jetzt möglicherweise nicht so wichtig.quelle
Doit1
,Doit2
etc. mit einerDoit
Methode , die viele verschiedene Implementierungen hat.doTheThing()
eine Methode für das Eingabesymbol festlegen. Dann müssen Sie die Karte nicht mehr pflegen.Ich bin stark für die Strategie, die in der Antwort von @DocBrown beschrieben ist .
Ich werde eine Verbesserung der Antwort vorschlagen.
Die Anrufe
kann verteilt werden. Sie müssen nicht zur selben Datei zurückkehren, um eine weitere Strategie hinzuzufügen, die dem Open-Closed-Prinzip noch besser entspricht.
Angenommen, Sie implementieren
Strategy1
in der Datei Strategy1.cpp. Sie können den folgenden Codeblock darin haben.Sie können denselben Code in jeder StategyN.cpp-Datei wiederholen. Wie Sie sehen können, wird dies eine Menge wiederholter Codes sein. Um die Codeduplizierung zu reduzieren, können Sie eine Vorlage verwenden, die in eine Datei eingefügt werden kann, auf die alle
Strategy
Klassen zugreifen können.Danach müssen Sie in Strategy1.cpp nur noch Folgendes verwenden:
Die entsprechende Zeile in StrategyN.cpp lautet:
Sie können die Verwendung von Vorlagen auf eine andere Ebene heben, indem Sie eine Klassenvorlage für die konkreten Strategieklassen verwenden.
Und dann anstelle von
Strategy1
verwendenConcreteStrategy<1>
.Ändern Sie die Hilfsklasse, um
Strategy
s zu registrieren, in:Ändern Sie den Code in Strateg1.cpp in:
Ändern Sie den Code in StrategN.cpp in:
quelle