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 itfromPrecomputed
, 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[][2]
, 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: readPrecomputedFormatA
, readPrecomputedFormatB
, and so on: this clutters the API.
Method 2: Make Foo
mutable
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?
Foo
be aware of howBar
is represented?Foo
is a special type of graph. I want to allow the user to build a precomputed graph, which means specifying the edges it contains. Internally,Foo
has a representation of an edge object and a container for storing edges, but the user just has to specify a 2d array of integers. But there are many different ways that the user can represent a 2d array, and I don't want to force the user to make a copy of his/her data to conform to my special standard. It isn't as simple as having an addEdge(int,int) method, since the tree shouldn't be mutable.