Builder

There are two flavours of Builder pattern as far as I am concerned. They are different as they present themselves in different problem contexts and solve different forces even though they look very similar from the outside. The first is the Stream Builder.

When you have data or an event stream used to construct a complicated object, you may desire different final objects based on the same stream of events. The example provided in the GoF book had builders consuming events produced when reading an RTF file. ASCII, LaTeX, and GUI Widget builders handled the text and formatting events; each builder dealt with the events in their own way.

A Stream Builder does not have to construct a complicated object. The GoF example converts from RTF to ASCII. You can use a Stream Builder for structured translations. Converting from YAML to JSON or vice-versa makes just as much sense. The core principle is that a concrete Stream Builder should consume events. The last event is often a finalisation step (GetProduct in one example), which seals the translation. If you require some last-minute bookkeeping, you can use this last event to trigger that work.

In effect, a Stream Builder is a way to take on the temporal coupling of events and data and convert it into another set of events and data. Under this interpretation, the disjoint temporal coupling requirements of the two different forms might necessitate a Stream Builder to maintain some considerable intermediate state before closing. The builder may need to hold instructions and data for later reference, to be sorted, or to be produced in a different order when translated into the new structure.

We often encounter conflicts when selecting the granularity of calls for a Stream Builder. What is too fine for one class might be too coarse for another. Another issue which can recur is how to refer to the results of previous actions in the build sequence.

That was the first type of builder. The other type of builder is the type which can ignore temporal coupling, and instead, all events are about pre-configuring before construction. The Expert Builder handles this other case where it’s not about interpreting events but directing construction.

There is almost an example of the Expert Builder in the GoF book with the MazeBuilder. The point of the Expert Builder is that it solves construction problems for you. It can return errors when it detects irreconcilable conflicts and may attempt to resolve constraints given the specifications provided by the director’s events. You generally find this type of builder supporting GUI-driven directors or scripting systems. The difference with this builder is that it commonly has a verification method to determine whether a configuration is complete and valid.

What’s shared by both builders is the concept of a director. There will be something providing events. Whether ordered or not, they must come from somewhere, so the director should be considered part of the pattern definition.

Both types of abstract Builder define the events which can be fed to the concrete builders, so they need updating when a new, more complex director arrives, but not when a new concrete Builder appears.

I suspect there is only one builder type in the GoF book because of the similarity of the final object diagrams. You can have an Expert Stream Builder without any conflict. Without a problem-centred approach to documenting patterns, patterns with neatly overlapping solutions will always suffer from a narrowing. Directors for both types of builders can be anything which emits events. They could be structured file readers, scripts, or functions. The builder must be able to accept these events and optionally handle a finalising step.

You can implement a builder with a dictionary or two—one for the methods and one for the current state.

“I build houses. Let me know how you want it constructed. How many bedrooms? How many floors? Do you need a driveway or garden?”