Suppose I'm writing some C++ code to visualize "Foo" objects. I have two ways of getting a "Foo": computing it from data, or from taking the pieces of a precomputed "Foo" and building a new "Foo".
Now, once a "Foo" is computed it's guaranteed to be good for visualization, but changing it may break this assumption. Therefore, I've decided to represent "Foos" in my code by a
Foo class that has no mutating methods: once it is constructed and initialized, it doesn't change.
But there's a second way to make a "Foo": build it from a precomputed "Foo"'s components. I've come up with several methods of building a
Foo from precomputed data:
Method 1: Constructor/Static methods
Perhaps the most obvious method would be to add a new constructor or a static method to
Foo, call it
fromPrecomputed, that would read the components of the precomputed Foo and make a new
Foo object, checking that it is valid. To explain why I'd like to shy away from this, I have to complicate my example: Let's say that one component of a "Foo" is a collection of "Bars". Now, in terms of implementation, sometimes a "Bar" is represented as a
std::vector<std::vector<Bar> >, sometimes as a
Bar array, sometimes as a
std::vector<std::pair<Bar,Bar> >, and so on... I could have the user reorganize their data into a standardized form and have a single constructor for this standard, but this might require the user to perform an extra copy. I don't want to provide a static method for each format:
readPrecomputedFormatB, and so on: this clutters the API.
Method 2: Make
If I exposed the
addBar(Bar) method of
Foo, then I could allow the user to iterate over their collection of "Bars" in their own way. This, however, makes
Foo mutable. So I could compute a
Foo that makes sense for visualization, then use
addBar to add a
Bar that makes the
Foo no longer a "Foo". Not good.
Method 3: Make a friend "builder" class
I make a class called
FooBuilder which has the
addBar(Bar) method exposed. I make
FooBuilder a friend of
Foo and add a constructor to
Foo that takes a
FooBuilder. On calling this constructor, it checks to make sure that
FooBuilder contains a valid "Foo" object, then swaps its empty representation of a Foo with what is inside the
FooBuilder. Everybody is happy.
The only "messiness" about method #3 is that it requires a friendship, but it's worth it to maintain encapsulation I think. But this has got me thinking: is this an established pattern? Or is there another, better way of doing this that I don't know about?