Ich habe eine IComposer
Schnittstelle in meinem c # Projekt:
CodeTree
ist eine Basisklasse, die List<CodeTree>
der Klassen enthält, die von CodeTree
erben. Zum Beispiel:
Ich kann ein paar Klassen haben, die IComposer
implementieren und in jedem habe ich die GenerateSnippet
, die die List<CodeTree>
durchlaufen und im Grunde folgendes tun:
Ich habe diese foreach
und if
Anweisungen in jeder Klasse wiederholt, die IComposer
implementiert.
Ich habe mich gefragt, ob es ein besseres Designmuster für einen solchen Fall gibt. Sagen wir mal, ich füge eine neue Klasse hinzu, die von CodeTree
erbt - ich müsste über alle Klassen gehen, die IComposer
implementieren und sie modifizieren.
Ich habe über das Visitor Design Pattern nachgedacht - war mir aber nicht sicher und nicht genau sicher, ob und wie es umgesetzt wird. Hat Visitor überhaupt die richtige Lösung für diesen Fall?
Verschieben Sie die Implementierung in Bezug auf die spezifischen Klassen in VariablesDecleration
und LoopsDecleration
und stellen Sie eine abstrakte Implementierung in CodeTree
bereit. Dann rufen Sie in Ihren Schleifen einfach diese Methode in CodeTree auf, ohne einen if ... else-Check.
Wie in den Kommentaren erwähnt, benötigen Sie möglicherweise Folgendes:
%Vor%Natürlich ist die Beziehung jetzt invertiert und Ihr Code-Baum oder sein Ersteller muss die Composer-Sammlung dafür definieren.
Ihre Frage ist, wie Sie Aktionen an verschiedenen Arten von Codebaumknoten durchführen können, richtig?
Beginnen Sie damit, eine neue Schnittstelle mit dem Namen INodeActor
zu deklarieren, die Ihnen den Vertrag darüber gibt, wie Ihr Code auf Codebaumknoten wirken kann. Die Definition würde etwa so aussehen:
Jetzt können Sie den folgenden Code verwenden:
%Vor%Und brich es auf:
%Vor%Komponist
Denken Sie an den Komponisten als Arbeitskoordinator. Es muss nicht wissen, wie die eigentliche Arbeit erledigt wird. Es liegt in der Verantwortung, die Codebaumstruktur zu durchlaufen und die Arbeit an alle registrierten Akteure zu delegieren.
%Vor%Verwendung
Sie können die Ausführung genau so anpassen, wie Sie möchten, ohne den Durchlauf oder vorhandenen Code ändern zu müssen. Somit folgt der Code nun den SOLID-Prinzipien.
%Vor% Wenn Sie ein Ergebnis erstellen möchten, könnten Sie einen Kontext einführen, der an die Methode INodeActor
invoke übergeben wird:
Wo der Kontext den zu verarbeitenden Knoten enthält, vielleicht ein StringBuilder
, um das Ergebnis zu speichern usw. Vergleichen Sie es mit HttpContext
in ASP.NET.
Sie können eine Basisklasse für alle Komponisten definieren und GenerateSnippet darin implementieren und vermeiden, diesen Code für jeden Komponisten neu zu schreiben. Darüber hinaus könnten Sie Ihre foreach-Schleife verbessern, indem Sie composer.DoStuff (); wie @Narayana vorgeschlagen.
%Vor%Ziehen Sie zunächst in Erwägung, GenerateSnippet aus der Basisklasse zu entfernen, von der andere Klassen geerbt wurden. Single-Verantwortung-Prinzip von SOLID will dies. Der Komponist muss komponieren, und CodeTree muss nur seine eigene Arbeit machen.
Nächster Schritt ist Ihr if-else-Block. Ich denke, dass Sie einfaches Wörterbuch verwenden können, um verschiedene Typen Ihrer CodeTree-Elemente zu speichern:
%Vor%Ich hoffe, Sie haben eine Idee. Sie sollten alle Typen beim Start der Anwendung mit der Composer RegisterCodeTreeType-Methode registrieren. Jetzt kommt es nicht darauf an, wie viele Typen Sie haben. Bitte beachten Sie, es ist nur ein schneller Code, verwenden Sie ihn sorgfältig.
Ok, diese If-Anweisungen zur Typprüfung müssen so geschrieben sein, wie Sie gemerkt haben, und es widerspricht dem Zweck der Abstraktion und Sub-Classing, wie Sie es bereits getan haben.
Sie möchten, dass Ihr Anrufcode gleich bleibt. (OCP) .
Momentan ist das CodeTree-Objekt dafür verantwortlich, die Logik jeder konkreten Implementierung herauszufinden.
Das Problem ist, dass die Verantwortung auf jeden konkreten gehört. Ihre for-Schleife sollte nur an den Schnittstellentyp IComposer
übergeben und die Methode string GenerateSnippet(CodeTree tree);
aufrufen, um das Ergebnis zu erhalten. Jeder konkrete sollte das Implementierungsdetail behandeln.
Anstatt CodeTree-Objekte zu durchlaufen, sollten Sie IComposer-Objekte durchlaufen.
Wenn Sie die Implementierung in ein bestimmtes Typobjekt verschieben, müssen Sie keine Änderungen am Ausführungscode vornehmen, sondern nur durch Hinzufügen eines neuen Typs erweitern, falls dies jemals geschieht. Wenn sich Ihr Implementierungsdetail stark unterscheidet, können Sie sich das Objektmustermuster ansehen. das wird mit allen Details umgehen und Ihr CodeTree-Objekt könnte einfacher bleiben.
Tags und Links c# design-patterns visitor