A follow up to another question (Making a design decision about reading model data from an input file).

I wish to ask another question regarding builder or factory pattern. (I read that builder is more complex than factory, and I may not need to use builder for now). So here is the data I have to read:

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   
   ...

There are many more tables like these. Some tables have parent, child relationships (Each coordinate system has grid line of its own). I have made structures that represent each table, like this:

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;
};

these data structures are incorporated to the model class, which will make a huge class since there are 50 odd data structures like this:

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

public:
Model() {} ...

}

each table has to have its set method and get method. This design worries me because if I decide to change it, it is going to be very time consuming. I appreciate any suggestion. I think the information here also will put the earlier question in a better light.

Now, I don't know where the builder or factory method should go, given the situation. I looked at some code and UML charts but I was not able to understand how to implement the factory, or builder to make structures required for my design. I have to have access to each table by name, because they might be subject to change inside the model, so for the time being I am avoiding making each of them a subclass of a virtual base class, so that I can store them in a container.

Also, does it make sense that instead of declaring an instance of the data struct, I should keep a pointer to them ? if all data structures are derived from a virtual base class called Record, then the model will be something like this:

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

std::Vector<Record*> data;

public:
Model() {} ...

}

I think it is extra work to allocate, dislocate memory for them, but it can help in managing the data and keep extra typing ? am I right in assuming that ?

  • I'm not sure the answer is either of your choices. The factory pattern is usually used in combination with polymorphism. The builder pattern is used when object construction is complex. You aren't using polymorphism, and each struct is fairly simple. this just seems like a straight up "how do I do data access" question. – Greg Burghardt Nov 16 at 0:56
  • "Factory" and "Builder" solve different problems. "Factory" would be suited if you have different derivations of the Model class (or different derivations of a common base class ModelBase or IModel), and you want to centralize the decision about which concrete derivation gets instantiated. I don't see this problem in your question, so what's your idea behind using a factory here? – Doc Brown Nov 16 at 6:59
up vote 5 down vote accepted

You are trying to solve a data access problem, and it requires a data access solution.

First, let's examine your proposed solutions, and why they don't solve the problems you have.

The Factory Pattern

The Factory Design Pattern (also called the Factory Method Pattern) is useful when you want to utilize polymorphism and you want to separate object construction completely from the implementing classes.

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.

(emphasis, mine)

And further down it elaborates on the problems this pattern solves:

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?

The problems you describe in your question are different from these. You aren't dealing with sub classes or polymorphism. The factory pattern isn't a solution.

The Builder Pattern

The Builder Pattern (from 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.

(emphasis, mine)

Here, again, we see a mismatch between the problem you are describing and the intended use of this pattern.

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?

(emphasis, mine)

The key here is the construction of an object (an object = 1 object) is complex. This could be due to a large number of constructor arguments, or due to the complexity of assembling its dependencies.

Individually, each struct or class is pretty simple, so the builder pattern is not a good fit either.

Data Access Patterns (The Solution)

The problems you are actually trying to solve are how to perform data access, and you may be looking for a Data Access Object.

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.

In your case, replace "database" with "text file". A related design pattern is the Repository Design Pattern, which breaks data access into 3 main solutions:

  • Repository — the public interface for "data access stuff"
  • Gateway — knows how to talk to an Oracle database or read/write to a text file. This would include serializing objects and structs to SQL or the data format expected in the text file.
  • Factory — maps data returned by the Gateway to the objects and structs used by the rest of your application

Ownership of Memory

Since you don't have the advantage/limitation of automatic management of memory, ownership of the memory allocated to these objects and structs is definitely a concern. Here you must make a decision:

  • Is the data access object responsible for cleaning up this memory?
  • Does the data access object expect the caller (client code) to take responsibility for freeing this memory?

If the data access object is created when the application starts, and lives until the application is shut down, the data access object could take ownership of this memory.

If the data access object is created on demand, and then disposed of, client code needs to make sure this memory is cleaned up.

Define this in the comments or documentation for the data access object, and enforce this in code review.

  • I like this approach. Looks much more flexible. Anything else I ask will expose my ignorance on the matter. Should I implement DAO myself ? The way I understand it, I should write the Gateway and Factory ? Is the Gateway the same as bridge GOF pattern ? – Ring Zero. Nov 16 at 18:15
  • I would say the gateway in the repository pattern is another variation of the bridge pattern. In fact it looks like the foundation of the repository pattern is a more organized and coordinated bridge pattern focused specifically on data access. And yes, you'll likely need to write these components yourself. – Greg Burghardt Nov 16 at 18:22
  • following the links you posted, I got to en.wikipedia.org/wiki/ODB_(C%2B%2B), How this ODB fits in the picture ? I can write a program to convert my text input to sqllite and then use ODB for persistence ? is this sound ? I have to say I just stumbled upon ODB and looked at two examples, so this is not an informed comment. – Ring Zero. Nov 16 at 19:58
  • Assistance with writing code is off topic for this site, however I'm sure you can convert the text to sqlite and use an existing library. – Greg Burghardt Nov 16 at 20:37

A builder would be "built" inside a factory invarient (method), thereby to read a text file, you would write 1 factory with a method to read said file. Now, if you need to incrementally build your model from the data you read (think nested data), the builder pattern inside the factory method would serve you well. However, a single model will probably suffice to load your data into.

  • Some pseudo code can help be very helpful hear. I have never used factory or builder patterns before. – Ring Zero. Nov 16 at 7:34

Given the size and complexity of your structure, a builder seems most appropriate, especially if your model is (or can be made) immutable. You'll have to accept some tight coupling between the builder and the model, but it's worth the trouble, especially if you'll need to build models in multiple places. A builder also allows you to encapsulate validation.

However, if your model is mutable and is only created in the one place, then a factory might be more appropriate and expedient and YAGNI comes into play.


In response to your other question, you should never store raw pointers in C++. The fact is std::unique_ptr has no downsides and it trivializes object destruction. When that vector goes out of scope, it won't free the memory it references as-written, but with a unique_ptr, it would.

I would create a vector for large quantities of repeating elements, especially if the quantity is likely to change, but for mid-sized components that are never shared, you might as well include them directly in the struct.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.