Pattern di fabbrica o modello di builder? quale è adatto per leggere i dati del modello a elementi finiti da un file di testo?

3

Un seguito di un'altra domanda ( Prendere una decisione progettuale sulla lettura dei dati del modello da un file di input ).

Desidero fare un'altra domanda riguardante il costruttore o il modello di fabbrica. (Ho letto che il builder è più complesso di fabbrica, e per il momento non ho bisogno di usare builder). 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-figlio (ogni sistema di coordinate ha una propria griglia). Ho creato delle 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 costituirà 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 ottenere il metodo. Questo design mi preoccupa perché se decido di cambiarlo, sarà molto dispendioso in termini di tempo. Apprezzo qualsiasi suggerimento. Penso che anche qui le informazioni metteranno la domanda precedente in una luce migliore.

Ora, non so dove dovrebbe andare il builder o il metodo factory, data la situazione. Ho esaminato alcuni grafici di codice e UML, ma non sono stato in grado di capire come implementare la fabbrica o il costruttore per creare le strutture necessarie per il mio progetto. Devo avere accesso a ciascun tavolo per nome, perché potrebbero essere soggetti a modifiche all'interno del modello, quindi per il momento sto evitando di fare di ognuno di essi una sottoclasse di una classe base virtuale, in modo che possa memorizzarli in un contenitore.

Inoltre, ha senso che invece di dichiarare un'istanza della struttura dei dati, dovrei tenere un puntatore a loro? se tutte le strutture dati derivano da una classe base virtuale chiamata Record, il modello sarà simile al seguente:

class Model
{
private:
ActiveDOF* activeDOF;
CoordinateSystem* coordinateSystem;
....

std::Vector<Record*> data;

public:
Model() {} ...

}

Penso che sia un lavoro extra da allocare, dislocare la memoria per loro, ma può aiutare a gestire i dati e mantenere la digitazione in più? ho ragione nell'assumerlo?

    
posta Ring Zero. 15.11.2018 - 21:44
fonte

3 risposte

5

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.

Il modello di fabbrica

Lo schema di disegno di fabbrica (detto anche modello di modello di fabbrica) è utile quando si desidera utilizzare il polimorfismo e si desidera separare completamente la costruzione di oggetti dalle classi di implementazione.

Wikipedia :

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

(enfasi, mia)

E più in basso si elabora i problemi risolti da questo schema:

The Factory Method design pattern solves problems like:

  • How can an object be created so that sub classes can redefine which class to instantiate?
  • How can a class defer instantiation to sub classes?

I problemi che descrivi nella tua domanda sono diversi da questi. Non hai a che fare con sottoclassi o polimorfismo. Lo schema di fabbrica non è una soluzione.

Il modello di generatore

Il modello di generatore (da Wikipedia ):

The Builder is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation.

(enfasi, mia)

Qui, di nuovo, vediamo una discrepanza tra il problema che stai descrivendo e l'uso previsto di questo modello.

The Builder design pattern solves problems like:

  • How can a class (the same construction process) create different representations of a complex object?
  • How can a class that includes creating a complex object be simplified?

(enfasi, mia)

La chiave qui è la costruzione di un oggetto (un oggetto = 1 oggetto) è complessa. Ciò potrebbe essere dovuto a un numero elevato di argomenti del costruttore o alla complessità dell'assemblaggio delle sue dipendenze.

Individualmente, ogni struct o classe è piuttosto semplice, quindi anche il pattern builder non è adatto.

Modelli di accesso ai dati (la soluzione)

I problemi che effettivamente in realtà cercano di risolvere sono come eseguire l'accesso ai dati, e potresti cercare un Oggetto di accesso ai dati .

In computer software, a data access object (DAO) is an object that provides an abstract interface to some type of database or other persistence mechanism. By mapping application calls to the persistence layer, the DAO provides some specific data operations without exposing details of the database.

Nel tuo caso, sostituisci "database" con "file di testo". Un modello di progettazione correlato è Pattern di progettazione del repository , che interrompe l'accesso ai dati in 3 soluzioni principali:

  • Repository - l'interfaccia pubblica per "materiale di accesso ai dati"
  • Gateway: sa come parlare con un database Oracle o leggere / scrivere su un file di testo. Ciò include la serializzazione di oggetti e strutture in SQL o il formato dei dati previsto nel file di testo.
  • Factory: esegue il mapping dei dati restituiti dal gateway agli oggetti e alle strutture utilizzate dal resto dell'applicazione

Proprietà della memoria

Dato che non hai il vantaggio / la limitazione della gestione automatica della memoria, la proprietà della memoria allocata a questi oggetti e strutture è sicuramente una preoccupazione. Qui devi prendere una decisione:

  • L'oggetto di accesso ai dati è responsabile della pulizia di questa memoria?
  • L'oggetto di accesso ai dati si aspetta che il chiamante (codice client) si assuma la responsabilità di liberare questa memoria?

Se l'oggetto di accesso ai dati viene creato all'avvio dell'applicazione e vive fino alla chiusura dell'applicazione, l'oggetto di accesso ai dati potrebbe diventare proprietario di questa memoria.

Se l'oggetto di accesso ai dati viene creato su richiesta, e quindi smaltito, il codice client deve essere sicuro che questa memoria venga pulita.

Definisci questo nei commenti o nella documentazione per l'oggetto di accesso ai dati e applicalo nella revisione del codice.

    
risposta data 16.11.2018 - 14:03
fonte
0

Data la dimensione e la complessità della tua struttura, un costruttore sembra il più appropriato, specialmente se il tuo modello è (o può essere reso) immutabile. Dovrai accettare un accoppiamento stretto tra il builder e il modello, ma ne vale la pena, soprattutto se dovrai creare modelli in più posizioni. Un costruttore ti consente anche di incapsulare la convalida.

Tuttavia, se il tuo modello è mutabile e viene creato solo in un posto, allora una fabbrica potrebbe essere più appropriata e utile e YAGNI entra in gioco.

In risposta alla tua altra domanda, non dovresti mai memorizzare puntatori grezzi in C ++. Il fatto è che std::unique_ptr non ha aspetti negativi e banalizza la distruzione dell'oggetto. Quando quel vettore esce dal campo di applicazione, non libererà la memoria a cui fa riferimento come scritto, 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 i componenti di medie dimensioni che non sono mai condivisi, potresti anche includerli direttamente nella struttura.

    
risposta data 16.11.2018 - 01:03
fonte
0

Un costruttore verrebbe "costruito" all'interno di un metodo invariante (metodo), in tal modo per leggere un file di testo, si scriverà 1 fabbrica con un metodo per leggere detto file. Ora, se è necessario incrementare progressivamente il modello dai dati che si leggono (si pensi ai dati annidati), il modello di builder all'interno del metodo factory potrebbe essere utile. Tuttavia, un singolo modello sarà probabilmente sufficiente per caricare i dati in.

    
risposta data 16.11.2018 - 00:57
fonte

Leggi altre domande sui tag