A seguito di unaltra domanda ( Prendere una decisione progettuale sulla lettura dei dati del modello da un file di input ).
Vorrei porre unaltra domanda sul modello di builder o di fabbrica. (Ho letto che builder è più complesso di factory e potrei non aver bisogno di usare builder per ora). Quindi ecco i dati che devo leggere:
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 ...
Ci sono molte altre tabelle come queste. Alcune tabelle hanno relazioni padre e figlio (ogni sistema di coordinate ha una propria griglia). Ho creato strutture che rappresentano ciascuna tabella, in questo modo:
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; };
queste strutture di dati sono incorporate nella classe del modello, che creerà una classe enorme poiché ci sono 50 strutture di dati dispari come questa:
class Model { private: ActiveDOF activeDOF; CoordinateSystem coordinateSystem; .... public: Model() {} ... }
ogni tabella deve avere il suo metodo set e metodo get. Questo design mi preoccupa perché se decido di cambiarlo, ci vorrà molto tempo. Apprezzo qualsiasi suggerimento. Penso che le informazioni qui fornite metteranno anche la domanda precedente in una luce migliore.
Ora, non so dove dovrebbe andare il metodo builder o factory, data la situazione. Ho guardato alcuni codici e grafici UML ma non ero in grado di capire come implementare la factory o il builder per creare le strutture richieste per il mio progetto. Devo avere accesso a ciascuna tabella per nome, perché potrebbero essere soggette a modifiche allinterno del modello, quindi per il momento evito di rendere ciascuna di esse una sottoclasse di una classe base virtuale, in modo da poterli memorizzare in un contenitore.
Inoltre, ha senso che invece di dichiarare unistanza della struttura dei dati, devo mantenere un puntatore a loro? Se tutte le strutture dei dati sono derivate da un classe base virtuale chiamata Record, quindi il modello sarà qualcosa del genere:
class Model { private: ActiveDOF* activeDOF; CoordinateSystem* coordinateSystem; .... std::Vector<Record*> data; public: Model() {} ... }
Penso che sia un lavoro extra per allocare, dislocare la memoria per loro, ma può aiutare nella gestione dei dati e mantenere la digitazione extra? Ho ragione a presumere che?
Commenti
Risposta
Stai tentando di risolvere un problema di accesso ai dati e richiede una soluzione di accesso ai dati.
Per prima cosa, esaminiamo le soluzioni proposte e perché non risolvono i problemi che hai.
Factory Pattern
Factory Design Pattern (chiamato anche Factory Method Pattern) è utile quando si desidera utilizzare il polimorfismo e si desidera separare completamente la costruzione di oggetti dalle classi di implementazione.
Nella programmazione basata su classi, il pattern del metodo factory è un pattern creazionale che utilizza metodi factory per affrontare il problema della creazione di oggetti senza dover specificare il classe esatta delloggetto che verrà creato. Questo viene fatto creando oggetti chiamando un metodo di fabbrica — specificato in uninterfaccia e implementata da classi figlie, o implementata in una classe base e facoltativamente sovrascritta da classi derivate — piuttosto che chiamando un costruttore .
(enfasi, mia)
E più avanti approfondisce i problemi risolti da questo pattern:
Il design pattern Factory Method risolve problemi come:
- Come può essere creato un oggetto in modo che le sottoclassi possano ridefinire quale classe istanziare?
- In che modo una classe può rinviare la creazione di istanze a sottoclassi?
I problemi che descrivi nella tua domanda sono diversi da questi. Non hai a che fare con sottoclassi o polimorfismo. Il pattern factory non è una soluzione.
The Builder Pattern
The Builder Pattern (da Wikipedia ):
Il Builder è un modello di progettazione progettato per fornire una soluzione flessibile a vari problemi di creazione di oggetti nella programmazione orientata agli oggetti. Lo scopo del modello di progettazione Builder è separare la costruzione di un oggetto complesso dalla sua rappresentazione.
(enfasi, mia)
Anche in questo caso, vediamo una mancata corrispondenza tra il problema che stai descrivendo e luso previsto di questo modello.
Il design pattern Builder risolve problemi come:
- Come può una classe (lo stesso processo di costruzione) creare rappresentazioni differenti di un oggetto complesso ?
- Come può una classe che include la creazione di un oggetto complesso essere semplificato?
(enfasi, mio)
La chiave qui è che la costruzione di un oggetto (un oggetto = 1 oggetto) è complessa. Ciò potrebbe essere dovuto a un gran numero di argomenti del costruttore, o alla complessità dellassemblaggio delle sue dipendenze.
Individualmente, ogni struttura o classe è piuttosto semplice, quindi neanche il modello del costruttore è adatto.
Modelli di accesso ai dati (la soluzione)
I problemi che effettivamente stai cercando di risolvere sono come eseguire laccesso ai dati e potresti essere alla ricerca di un Oggetto di accesso ai dati .
Nel software del computer, un oggetto di accesso ai dati (DAO) è un oggetto che fornisce uninterfaccia astratta a qualche tipo di database o altro meccanismo di persistenza. Mappando le chiamate dellapplicazione al livello di persistenza , il DAO fornisce alcune operazioni sui dati specifiche senza esporre i dettagli del database.
Nel tuo caso, sostituisci “database” con “file di testo”. Un modello di progettazione correlato è il Repository Design Pattern , che suddivide laccesso ai dati in 3 soluzioni principali:
- Repository — linterfaccia pubblica per “cose di accesso ai dati”
- Gateway — sa come parlare a un database Oracle o leggere / scrivere a un file di testo. Ciò includerebbe la serializzazione di oggetti e strutture in SQL o nel formato dati previsto nel file di testo.
- Factory — mappa i dati restituiti dal gateway agli oggetti e agli struct utilizzato dal resto della tua applicazione
Proprietà della memoria
Dato che non hai il vantaggio / limitazione della gestione automatica della memoria, la proprietà della memoria assegnata a questi oggetti e strutture sono sicuramente una preoccupazione. Qui devi prendere una decisione:
- Loggetto di accesso ai dati è responsabile della pulizia di questa memoria?
- Loggetto di accesso ai dati aspettarsi che il chiamante (codice client) si assuma la responsabilità di liberare questa memoria?
Se loggetto di accesso ai dati viene creato allavvio dellapplicazione e rimane attivo fino alla chiusura dellapplicazione, laccesso ai dati loggetto potrebbe assumere la proprietà di questa memoria.
Se loggetto di accesso ai dati viene creato su richiesta e quindi eliminato, il codice client deve assicurarsi che questa memoria sia pulita ned up.
Definiscilo nei commenti o nella documentazione per loggetto di accesso ai dati e applicalo nella revisione del codice.
Commenti
- Mi piace questo approccio. Sembra molto più flessibile. Qualsiasi altra cosa chiederò esporrà la mia ignoranza in merito. Devo implementare DAO da solo? Per come la vedo io, dovrei scrivere Gateway and Factory? Il gateway è lo stesso del pattern bridge GOF?
- Direi che il gateway nel pattern del repository è unaltra variazione del pattern bridge. In effetti, sembra che il fondamento del modello di repository sia un modello di bridge più organizzato e coordinato incentrato specificamente sullaccesso ai dati. E sì, ‘ dovrai probabilmente scrivere questi componenti da solo.
- seguendo i link che hai pubblicato, sono arrivato a en.wikipedia.org/wiki/ODB_(C%2B%2B) , come si inserisce questo ODB nellimmagine? Posso scrivere un programma per convertire il mio input di testo in sqllite e quindi utilizzare ODB per la persistenza? è questo suono? Devo dire che mi sono imbattuto in ODB e ho guardato due esempi, quindi questo non è un commento informato.
- Lassistenza con la scrittura del codice è fuori tema per questo sito, tuttavia ‘ sono sicuro che puoi convertire il testo in sqlite e utilizzare una libreria esistente.
Risposta
Un builder sarebbe “costruito” allinterno di un invarient di fabbrica (metodo), in tal modo per leggere un file di testo, scriveresti 1 factory con un metodo per leggere detto file. Ora, se hai bisogno di costruire in modo incrementale il tuo modello dai dati che leggi (pensa ai dati nidificati), il modello di builder allinterno del metodo factory ti servirebbe bene. Tuttavia, un singolo modello sarà probabilmente sufficiente per caricare i dati.
Commenti
- Alcuni pseudo codice possono essere molto utili per lascolto. Non ho mai utilizzato pattern factory o builder prima dora.
Answer
Date le dimensioni e la complessità della vostra struttura, un costruttore sembra più appropriato, soprattutto se il tuo modello è (o può essere realizzato) immutabile. Dovrai accettare un accoppiamento stretto tra il builder e il modello, ma ne vale la pena, soprattutto se avrai bisogno di costruire modelli in più posizioni. Un builder ti consente anche di incapsulare la convalida.
Tuttavia, se il tuo modello è mutevole e viene creato solo in un posto, allora una fabbrica potrebbe essere più appropriata e conveniente e YAGNI entra in gioco.
In risposta alla tua altra domanda , non dovresti mai memorizzare puntatori non elaborati in C ++. Il fatto è che std::unique_ptr
non ha svantaggi e banalizza la distruzione degli oggetti. Quando quel vettore esce dallambito, non libera la memoria riferimenti come scritti, ma con un unique_ptr, lo farebbe.
Creerei un vettore per grandi quantità di elementi ripetuti, specialmente se è probabile che la quantità cambi, ma per componenti di medie dimensioni che non sono mai condivisi, potresti anche includerli direttamente nella struttura.
Model
(o derivazioni diverse di una classe base comuneModelBase
oIModel
) e si desidera centralizzare la decisione su quale derivazione concreta viene istanziata. Non ‘ non vedo questo problema nella tua domanda, quindi qual è ‘ la tua idea dietro lutilizzo di una fabbrica qui?