Suite à une autre question ( Prendre une décision de conception concernant la lecture des données du modèle à partir dun fichier dentrée ).
Je souhaite poser une autre question concernant le constructeur ou le modèle dusine. (Jai lu que le constructeur est plus complexe que lusine, et je nai peut-être pas besoin dutiliser le constructeur pour le moment). Voici donc les données que je dois lire:
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 ...
Il y a beaucoup plus de tables comme celles-ci. Certaines tables ont des relations parent-enfant (chaque système de coordonnées a sa propre ligne de quadrillage). Jai créé des structures qui représentent chaque table, comme ceci:
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; };
ces structures de données sont incorporées à la classe de modèle, ce qui fera une classe énorme car il y a 50 structures de données impaires comme celle-ci:
class Model { private: ActiveDOF activeDOF; CoordinateSystem coordinateSystem; .... public: Model() {} ... }
chaque table doit avoir sa méthode set et get méthode. Cette conception minquiète car si je décide de la changer, cela prendra beaucoup de temps. Japprécie toute suggestion. Je pense que les informations présentées ici permettront également de mieux éclairer la question précédente.
Maintenant, je ne sais pas où la méthode du constructeur ou de lusine devrait aller, étant donné la situation. Jai regardé du code et des graphiques UML mais je nai pas été en mesure de comprendre comment implémenter lusine ou le générateur pour créer les structures nécessaires à ma conception. Je dois avoir accès à chaque table par son nom, car elles peuvent être sujettes à changement à lintérieur du modèle, donc pour le moment jévite de faire de chacune delles une sous-classe dune classe de base virtuelle, afin que je puisse les stocker dans un conteneur.
Aussi, est-il logique quau lieu de déclarer une instance de la structure de données, je devrais garder un pointeur vers eux? si toutes les structures de données sont dérivées dun classe de base virtuelle appelée Record, alors le modèle sera quelque chose comme ceci:
class Model { private: ActiveDOF* activeDOF; CoordinateSystem* coordinateSystem; .... std::Vector<Record*> data; public: Model() {} ... }
Je pense que cest un travail supplémentaire pour allouer, disloquer la mémoire pour eux, mais il peut aider à gérer les données et continuer à taper davantage? Ai-je raison de supposer cela?
Commentaires
Réponse
Vous essayez de résoudre un problème daccès aux données, et il nécessite une solution daccès aux données.
Tout dabord, examinons les solutions proposées et pourquoi elles ne résolvent pas les problèmes que vous rencontrez.
Le modèle dusine
Le modèle de conception dusine (également appelé modèle de méthode dusine) est utile lorsque vous souhaitez utiliser le polymorphisme et que vous souhaitez séparer complètement la construction dobjet des classes dimplémentation.
Dans la programmation basée sur les classes, le modèle de méthode dusine est un modèle de création qui utilise des méthodes dusine pour traiter le problème de la création dobjets sans avoir à spécifier le classe exacte de lobjet qui sera créé. Cela se fait en créant des objets en appelant une méthode dusine — soit spécifiée dans une interface et implémentée par des classes enfants, ou implémentée dans une classe de base et éventuellement remplacée par des classes dérivées — plutôt quen appelant un constructeur .
(cest moi qui souligne)
Et plus bas, il élabore sur les problèmes que ce modèle résout:
Le modèle de conception de la méthode dusine résout des problèmes tels que:
- Comment créer un objet pour que les sous-classes puissent redéfinir la classe à instancier?
- Comment une classe peut-elle différer linstanciation vers des sous-classes ?
Les problèmes que vous décrivez dans votre question sont différents de ceux-ci. Vous nêtes pas confronté à des sous-classes ou à un polymorphisme. Le modèle dusine nest pas une solution.
Le modèle du générateur
Le modèle du générateur (de Wikipedia ):
The Builder est un modèle de conception conçu pour fournir une solution flexible à divers problèmes de création dobjets dans la programmation orientée objet. Lintention du modèle de conception Builder est de séparer la construction dun objet complexe de sa représentation.
(cest moi qui souligne)
Ici encore, nous voyons un décalage entre le problème que vous décrivez et lutilisation prévue de ce modèle.
Le modèle de conception Builder résout des problèmes tels que:
- Comment une classe (le même processus de construction) peut-elle créer différentes représentations dun objet complexe ?
- Comment une classe qui inclut la création dun objet complexe simplifié?
(cest moi qui souligne)
La clé ici est la construction dun objet (un objet = 1 objet) est complexe. Cela peut être dû à un grand nombre darguments de constructeur, ou à la complexité dassemblage de ses dépendances.
Individuellement, chaque structure ou classe est assez simple, donc le modèle de constructeur ne convient pas non plus.
Modèles daccès aux données (la solution)
Les problèmes que vous essayez en fait de résoudre sont de savoir comment accéder aux données, et vous recherchez peut-être un Objet daccès aux données .
Dans un logiciel informatique, un objet daccès aux données (DAO) est un objet qui fournit une interface abstraite vers un type de base de données ou un autre mécanisme de persistance. En mappant les appels d’application à la couche de persistance , le DAO fournit des opérations de données spécifiques sans exposer les détails de la base de données.
Dans votre cas, remplacez « base de données » par « fichier texte ». Un modèle de conception associé est le Modèle de conception de référentiel , qui divise laccès aux données en 3 solutions principales:
- Référentiel — linterface publique pour les « données daccès aux données »
- Gateway — sait comment parler à une base de données Oracle ou lire / écrire dans un fichier texte. Cela inclurait la sérialisation des objets et des structures en SQL ou au format de données attendu dans le fichier texte.
- Factory — mappe les données renvoyées par la passerelle vers les objets et les structures utilisé par le reste de votre application
Propriété de la mémoire
Puisque vous n’avez pas l’avantage / la limitation de la gestion automatique de la mémoire, la propriété de la mémoire allouée à ces objets et structures sont définitivement un problème. Ici, vous devez prendre une décision:
- Lobjet daccès aux données est-il responsable du nettoyage de cette mémoire?
- Lobjet daccès aux données sattendre à ce que lappelant (code client) prenne la responsabilité de libérer cette mémoire?
Si lobjet daccès aux données est créé au démarrage de lapplication, et vit jusquà ce que lapplication soit arrêtée, laccès aux données objet pourrait prendre possession de cette mémoire.
Si lobjet daccès aux données est créé à la demande, puis éliminé, le code client doit sassurer que cette mémoire est effacée
Définissez ceci dans les commentaires ou la documentation de lobjet daccès aux données, et appliquez-le dans la révision du code.
Commentaires
- Jaime cette approche. Semble beaucoup plus flexible. Tout ce que je demanderai exposera mon ignorance à ce sujet. Dois-je implémenter DAO moi-même? La façon dont je le comprends, je devrais écrire la passerelle et lusine? La passerelle est-elle la même que le modèle de pont GOF?
- Je dirais que la passerelle dans le modèle de référentiel est une autre variante du modèle de pont. En fait, il semble que le fondement du modèle de référentiel soit un modèle de pont plus organisé et coordonné spécifiquement axé sur laccès aux données. Et oui, vous ‘ devrez probablement écrire vous-même ces composants.
- en suivant les liens que vous avez publiés, je suis arrivé à en.wikipedia.org/wiki/ODB_(C%2B%2B) , Comment cet ODB sintègre-t-il dans limage? Je peux écrire un programme pour convertir mon entrée de texte en sqllite, puis utiliser ODB pour la persistance? est ce son? Je dois dire que je suis tombé sur ODB et jai regardé deux exemples, donc ce nest pas un commentaire éclairé.
- Laide à la rédaction de code nest pas un sujet pour ce site, mais je ‘ suis sûr que vous pouvez convertir le texte en sqlite et utiliser une bibliothèque existante.
Réponse
Un constructeur serait « construit » à lintérieur dune usine invarient (méthode), pour ainsi lire un fichier texte, vous écririez 1 usine avec une méthode pour lire ledit fichier. Maintenant, si vous avez besoin de créer votre modèle de manière incrémentielle à partir des données que vous lisez (pensez aux données imbriquées), le modèle de générateur à lintérieur de la méthode de fabrique vous sera très utile. Cependant, un seul modèle suffira probablement pour charger vos données.
Commentaires
- Certains pseudo-code peuvent être très utiles. Je nai jamais utilisé de modèles dusine ou de constructeur auparavant.
Réponse
Compte tenu de la taille et de la complexité de votre structure, un constructeur semble le plus approprié, surtout si votre modèle est (ou peut être rendu) immuable. Vous devrez accepter un couplage étroit entre le générateur et le modèle, mais cela en vaut la peine, surtout si vous devez créer des modèles à plusieurs endroits. Un générateur vous permet également dencapsuler la validation.
Cependant, si votre modèle est modifiable et nest créé quà un seul endroit, alors une usine peut être plus appropriée et plus rapide et YAGNI entre en jeu.
En réponse à votre autre question , vous ne devez jamais stocker de pointeurs bruts en C ++. Le fait est que std::unique_ptr
n’a aucun inconvénient et il banalise la destruction d’objets. Lorsque ce vecteur est hors de portée, il ne libère pas la mémoire références telles quécrites, mais avec un unique_ptr, ce serait le cas.
Je créerais un vecteur pour de grandes quantités déléments répétitifs, surtout si la quantité est susceptible de changer, mais pour les composants de taille moyenne qui ne sont jamais partagés, vous pouvez aussi bien les inclure directement dans la structure.
Model
(ou différentes dérivations dune classe de base communeModelBase
ouIModel
), et vous voulez centraliser la décision sur la dérivation concrète qui sera instanciée. Je ne vois ‘ pas ce problème dans votre question, alors quelle est ‘ lidée dutiliser une usine ici?