Fabrikmuster oder Baumeistermuster? Welches eignet sich zum Lesen von Finite-Elemente-Modelldaten aus einer Textdatei?

Eine Fortsetzung einer anderen Frage ( Treffen einer Entwurfsentscheidung zum Lesen von Modelldaten aus einer Eingabedatei ).

Ich möchte eine weitere Frage zum Builder- oder Factory-Muster stellen. (Ich habe gelesen, dass der Builder komplexer als die Fabrik ist und ich den Builder möglicherweise vorerst nicht verwenden muss.) Hier sind die Daten, die ich lesen muss:

TABLE: "DEGREES OF FREEDOM" X=Yes Y=Yes Z=Yes R1=Yes R2=Yes R3=Yes TABLE: "ANALYSIS OPTIONS" Solver=Advanced SolverProc=Advanced TABLE: "COORDINATE SYSTEMS" Name=GLOBAL Type=Cartesian X=0 Y=0 Z=0 TABLE: "GRID LINES" CoordSys=GLOBAL AxisDir=X GridID=A XRYZCoord=-720 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=B XRYZCoord=-432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=C XRYZCoord=-144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=D XRYZCoord=144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=E XRYZCoord=432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=F XRYZCoord=720 LineColor=Gray8Dark Visible=Yes ... 

Es gibt viele weitere Tabellen wie diese. Einige Tabellen haben übergeordnete und untergeordnete Beziehungen (jedes Koordinatensystem hat eine eigene Gitterlinie). Ich habe Strukturen erstellt, die jede Tabelle darstellen, wie folgt:

struct ActiveDOF { bool Ux; bool Uy; bool Uz; bool Rx; bool Ry; bool Rz; }; struct GridLine { enum Direction{X, Y, Z}; enum Type{PRIMARY, SECONDARY}; enum Location{START, END}; std::string coodSystem; Direction direction; std::string gridID; float XRYZ; Type lineType; QColor color; bool visible; Location bubleLoc; bool allVisible; float bubleSize; }; struct CoordinateSystem { std::string name; std::string type; QVector3D center; // center x, center y, cetner z QVector3D about; // aboutx, about y, about z std::vector<GridLine> gridLines; }; 

Diese Datenstrukturen werden in die Modellklasse integriert, wodurch eine große Klasse entsteht, da es solche gibt 50 ungerade Datenstrukturen wie diese:

class Model { private: ActiveDOF activeDOF; CoordinateSystem coordinateSystem; .... public: Model() {} ... } 

Jede Tabelle muss ihre Set-Methode und Get-Methode haben. Dieses Design macht mir Sorgen, denn wenn ich mich entscheide, es zu ändern, wird es sehr zeitaufwändig sein. Ich freue mich über jeden Vorschlag. Ich denke, die Informationen hier werden auch die frühere Frage in ein besseres Licht rücken.

Jetzt weiß ich angesichts der Situation nicht, wohin der Builder oder die Factory-Methode gehen soll. Ich habe mir einige Code- und UML-Diagramme angesehen, konnte aber nicht verstehen, wie die Factory oder der Builder implementiert wird Um Strukturen zu erstellen, die für mein Design erforderlich sind, muss ich über den Namen auf jede Tabelle zugreifen können, da sie sich innerhalb des Modells ändern können. Daher vermeide ich es vorerst, jede von ihnen zu einer Unterklasse einer virtuellen Basisklasse zu machen. Damit ich sie in einem Container speichern kann.

Ist es auch sinnvoll, statt eine Instanz der Datenstruktur zu deklarieren, einen Zeiger auf sie zu behalten, wenn alle Datenstrukturen von a abgeleitet sind Virtuelle Basisklasse namens Record, dann wird das Modell ungefähr so aussehen:

class Model { private: ActiveDOF* activeDOF; CoordinateSystem* coordinateSystem; .... std::Vector<Record*> data; public: Model() {} ... } 

Ich denke, es ist zusätzliche Arbeit, Speicher für sie zuzuweisen, zu verschieben, aber es Kann ich bei der Verwaltung der Daten helfen und zusätzliche Eingaben vornehmen? Bin ich zu Recht davon ausgegangen, dass?

Kommentare

  • I ‚ mn Ich bin mir nicht sicher, ob die Antwort eine Ihrer Entscheidungen ist. Das Fabrikmuster wird normalerweise in Kombination mit Polymorphismus verwendet. Das Builder-Muster wird verwendet, wenn die Objektkonstruktion komplex ist. Sie verwenden nicht ‚ den Polymorphismus, und jede Struktur ist ziemlich einfach. Dies scheint nur eine direkte Frage zu sein. “ Wie mache ich den Datenzugriff? „.
  • “ Factory “ und “ Builder “ lösen verschiedene Probleme . “ Factory “ ist geeignet, wenn Sie unterschiedliche Ableitungen der Klasse Model (oder) haben verschiedene Ableitungen einer gemeinsamen Basisklasse ModelBase oder IModel), und Sie möchten die Entscheidung darüber zentralisieren, welche konkrete Ableitung instanziiert wird. Ich sehe ‚ dieses Problem in Ihrer Frage nicht. Was ‚ ist Ihre Idee, eine Fabrik hier zu verwenden?

/ ul>

Antwort

Sie versuchen, ein Datenzugriffsproblem zu lösen erfordert eine Datenzugriffslösung.

Lassen Sie uns zunächst Ihre vorgeschlagenen Lösungen untersuchen und herausfinden, warum sie die Probleme, die Sie haben, nicht lösen.

Das Factory-Muster

Das Factory-Design-Muster (auch als Factory-Methodenmuster bezeichnet) ist nützlich, wenn Sie Polymorphismus verwenden und die Objektkonstruktion vollständig von den implementierenden Klassen trennen möchten.

Wikipedia :

In der klassenbasierten Programmierung Das Factory-Methodenmuster ist ein Erstellungsmuster , das Factory-Methoden verwendet, um das Problem des Erstellens von Objekten zu lösen, ohne das angeben zu müssen genaue Klasse des Objekts, das erstellt wird. Dies erfolgt durch Erstellen von Objekten durch Aufrufen einer Factory-Methode —, die entweder in angegeben ist eine Schnittstelle, die von untergeordneten Klassen implementiert oder in einer Basisklasse implementiert und optional von abgeleiteten Klassen — überschrieben wird, anstatt einen Konstruktor aufzurufen .

(Hervorhebung, meine)

Und weiter unten wird näher darauf eingegangen Die Probleme, die dieses Muster löst:

Das Entwurfsmuster der Factory-Methode löst Probleme wie:

  • Wie kann ein Objekt erstellt werden? damit Unterklassen neu definieren können, welche Klasse instanziiert werden soll?
  • Wie kann eine Klasse die Instanziierung auf Unterklassen verschieben?

Die Probleme, die Sie in Ihrer Frage beschreiben, unterscheiden sich von diesen. Sie haben es nicht mit Unterklassen oder Polymorphismus zu tun. Das Fabrikmuster ist keine Lösung.

Das Builder-Muster

Das Builder-Muster (aus Wikipedia ):

Der Builder ist ein Entwurfsmuster, das eine flexible Lösung für verschiedene Objekterstellungsprobleme bei der objektorientierten Programmierung bietet. Mit dem Builder-Entwurfsmuster soll die Konstruktion eines komplexen Objekts von seiner Darstellung getrennt werden.

(Hervorhebung, meine)

Auch hier sehen wir eine Nichtübereinstimmung zwischen dem von Ihnen beschriebenen Problem und der beabsichtigten Verwendung dieses Musters.

Das Builder-Entwurfsmuster löst Probleme wie:

  • Wie kann eine Klasse (derselbe Konstruktionsprozess) unterschiedliche Darstellungen eines komplexes Objekt ?
  • Wie kann eine Klasse, die das Erstellen eines komplexes Objekt vereinfacht werden?

(Hervorhebung, meins)

Der Schlüssel hier ist, dass die Konstruktion eines Objekts (ein Objekt = 1 Objekt) komplex ist. Dies kann auf eine große Anzahl von Konstruktorargumenten oder auf die Komplexität des Zusammenstellens seiner Abhängigkeiten zurückzuführen sein.

Jede Struktur oder Klasse ist einzeln ziemlich einfach, sodass das Builder-Muster auch nicht gut passt.

Datenzugriffsmuster (die Lösung)

Die Probleme, die Sie tatsächlich zu lösen versuchen, sind die Durchführung des Datenzugriffs, und Sie suchen möglicherweise nach einem Datenzugriffsobjekt .

In Computersoftware ein Datenzugriffsobjekt (DAO) ist ein Objekt, das eine abstrakte -Schnittstelle für eine Art Datenbank oder einen anderen Persistenzmechanismus bereitstellt. Durch Zuordnen von Anwendungsaufrufen zur Persistenzschicht Das DAO stellt einige spezifische Datenoperationen bereit, ohne Details der Datenbank offenzulegen.

Ersetzen Sie in Ihrem Fall „Datenbank“ durch „Textdatei“. Ein verwandtes Entwurfsmuster ist das Repository-Entwurfsmuster , das den Datenzugriff in drei Hauptlösungen unterteilt:

  • Repository — die öffentliche Schnittstelle für „Datenzugriffsmaterial“
  • Gateway — kann mit einer Oracle-Datenbank kommunizieren oder lesen / schreiben eine Textdatei. Dies würde das Serialisieren von Objekten und Strukturen in SQL oder das in der Textdatei erwartete Datenformat umfassen.
  • Factory — ordnet die vom Gateway zurückgegebenen Daten den Objekten und Strukturen zu Wird vom Rest Ihrer Anwendung verwendet.

Besitz des Speichers

Da Sie nicht den Vorteil / die Einschränkung der automatischen Verwaltung des Speichers haben, wird der Besitz des Speichers zugewiesen Diese Objekte und Strukturen sind definitiv ein Problem. Hier müssen Sie eine Entscheidung treffen:

  • Ist das Datenzugriffsobjekt für die Bereinigung dieses Speichers verantwortlich?
  • Ist das Datenzugriffsobjekt Erwarten Sie, dass der Anrufer (Client-Code) die Verantwortung für die Freigabe dieses Speichers übernimmt?

Wenn das Datenzugriffsobjekt beim Start der Anwendung erstellt wird und bis zum Herunterfahren der Anwendung gültig ist, wird der Datenzugriff ausgeführt Das Objekt könnte den Besitz dieses Speichers übernehmen.

Wenn das Datenzugriffsobjekt bei Bedarf erstellt und dann entsorgt wird, muss der Clientcode sicherstellen, dass dieser Speicher sauber ist

Definieren Sie dies in den Kommentaren oder in der Dokumentation für das Datenzugriffsobjekt und erzwingen Sie dies in der Codeüberprüfung.

Kommentare

  • Ich mag diesen Ansatz. Sieht viel flexibler aus. Alles andere, was ich frage, wird meine Unwissenheit in dieser Angelegenheit aufdecken. Soll ich DAO selbst implementieren? So wie ich es verstehe, sollte ich das Gateway und die Factory schreiben? Entspricht das Gateway dem GOF-Muster der Brücke?
  • Ich würde sagen, dass das Gateway im Repository-Muster eine weitere Variation des Brückenmusters ist. Tatsächlich sieht es so aus, als ob die Grundlage des Repository-Musters ein besser organisiertes und koordiniertes Brückenmuster ist, das sich speziell auf den Datenzugriff konzentriert. Und ja, Sie ‚ müssen diese Komponenten wahrscheinlich selbst schreiben.
  • Nach den von Ihnen geposteten Links kam ich zu de.wikipedia.org/wiki/ODB_(C%2B%2B) , Wie passt diese ODB in das Bild? Ich kann ein Programm schreiben, um meine Texteingabe in SQLite zu konvertieren und dann ODB für die Persistenz zu verwenden. ist das Geräusch? Ich muss sagen, ich bin gerade auf ODB gestoßen und habe mir zwei Beispiele angesehen, daher ist dies kein informierter Kommentar.
  • Die Unterstützung beim Schreiben von Code ist für diese Site kein Thema. Ich ‚ bin jedoch sicher, dass Sie den Text in SQLite konvertieren und eine vorhandene Bibliothek verwenden können.

Antwort

Ein Builder würde in einer Factory Invarient (Methode) „erstellt“, um eine Textdatei zu lesen. Sie würden 1 Factory mit einer Methode zum Lesen dieser Datei schreiben. Wenn Sie Ihr Modell nun schrittweise aus den von Ihnen gelesenen Daten erstellen müssen (denken Sie an verschachtelte Daten), ist das Builder-Muster in der Factory-Methode hilfreich. Ein einzelnes Modell wird jedoch wahrscheinlich ausreichen, um Ihre Daten in zu laden.

Kommentare

  • Einige Pseudocodes können beim Hören sehr hilfreich sein. Ich habe noch nie Factory- oder Builder-Muster verwendet.

Antwort

Angesichts der Größe und Komplexität Ihrer Struktur Ein Builder scheint am besten geeignet zu sein, insbesondere wenn Ihr Modell unveränderlich ist (oder hergestellt werden kann). Sie müssen eine enge Kopplung zwischen dem Builder und dem Modell akzeptieren, aber die Mühe lohnt sich, insbesondere wenn Sie Modelle an mehreren Stellen erstellen müssen. Mit einem Builder können Sie auch die Validierung kapseln.

Wenn Ihr Modell jedoch veränderlich ist und nur an einer Stelle erstellt wird, ist eine Fabrik möglicherweise geeigneter und zweckmäßiger, und YAGNI kommt ins Spiel.


Als Antwort auf Ihre andere Frage sollten Sie niemals rohe Zeiger in C ++ speichern. Die Tatsache ist, dass std::unique_ptr keine Nachteile hat und die Objektzerstörung trivialisiert. Wenn dieser Vektor den Gültigkeitsbereich verlässt, wird der Speicher nicht freigegeben Verweise wie geschrieben, aber mit einem unique_ptr würde es.

Ich würde einen Vektor für große Mengen sich wiederholender Elemente erstellen, insbesondere wenn sich die Menge wahrscheinlich ändert. Für mittelgroße Komponenten, die niemals gemeinsam genutzt werden, können Sie sie jedoch auch direkt in die Struktur aufnehmen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.