Bestes Entwurfsmuster für mehrere if-Anweisungen in einer Schnittstellenimplementierung

8

Ich habe eine IComposer Schnittstelle in meinem c # Projekt:

%Vor%

CodeTree ist eine Basisklasse, die List<CodeTree> der Klassen enthält, die von CodeTree erben. Zum Beispiel:

%Vor%

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:

%Vor%

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?

    
developer82 21.12.2015, 06:09
quelle

6 Antworten

8

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.

%Vor%

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.

    
Narayana 21.12.2015 06:15
quelle
4

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:

%Vor%

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:

%Vor%

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.

    
jgauffin 21.12.2015 08:47
quelle
2

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%     
ehh 21.12.2015 07:08
quelle
2

Vielleicht könnte Dependency Inversion helfen?

%Vor%     
Matt Searles 21.12.2015 07:09
quelle
2

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.

    
Dzianis Yafimau 21.12.2015 08:43
quelle
1

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.

    
Eugène 21.12.2015 06:43
quelle

Tags und Links