Builder: Design Pattern or Obsession?
Recently, I had a familiar thing happen: I recognized that I needed a class to make an instance of another class based on some preferences a user had configured. So I started with a factory. Looking back, I have to kind of laugh at the fact that I actually thought for a minute I wouldn‘t end up with a builder. So my factory created something super simple, that made my first test pass, and I was happy. Then I started to handle more sections of the user preferences, and the factory started to get complicated. Soon as I thought ‘ok, I should put a private method in here for constructing I realized it was time for Builder.
Ironically, I had just been writing about C and thought ‘is builder the procedural refuge of would-be OOers?‘ The answer, I think is ‘it could be, but there‘s no reason it has to be.‘
It is true that the Director needs to call the build methods in a specific order, but most of the time in builders I make, the order really doesn‘t matter. What matters is that Builder is the creational pattern version of Template Method: it‘s making sure that the construction of something obeys a protocol. What are the reasons for this? Well the usual ones apply of course:
- protocols inject naming into a process, and they encourage separation of concerns. If my app is suddenly not handling preference construction properly, it will surely help to know which part of the preferences are causing problems.
- the use of a protocol also lends itself to extension. Suppose I have some special behavior I want to add to just one part of the construction process. I can either provide a subclass with a single method (and ignore all the other details of the construction process), or I could go add some logic to the base class.
- when constructing the parts of something explicitly, we are making it more likely that those who come after will only mess with the things they need to mess with.
The other question I tend to ask myself a lot is why does the world need so many builders? I am not drawn to the argument that design patterns owe their existence to language lacks, but in this case, some of that is true. Per my earlier posts, I was totally head over heels for the Bloch static builder, but in Objective C, it‘s not really needed. The alternative, init methods with a bunch of named params (I know they are not literally named args, so spare the correction) combined with a protocol to shut off access to the set methods is actually pretty nice. If you think about it, the whole debate that was sparked when C++ stipulated that .h++ files ought contain the ‘interface,‘ the natural question: ‘where do the private parts go?‘ is really only answered by Objective-C. When I first started using it (not having done C++ since 1995), I thought ‘OMG, I am going to blow something up having to go back and forth between header and impl all day long (but thankfully Xcode makes that super simple).) But, in fact, in O-C, when you declare the interface, you leave the private stuff out. The first couple examples I looked at of doing private methods in inline Categories showed the interface and implementation in the .m file. I couldn‘t get that to work, so the interface def did end up in the .h file, but if you think about it, the .m for both makes more sense and achieves that dream from so long ago of really keeping the business of how the sausage is made behind the curtain as it were.
Director/Builder is from this same vein, really the only one we have: indirection. James Coplien's book Advanced C++ which really blew the door open on the patterns movement, called it envelope/letter.
But the Bloch/O-C constructs address the construction of an object. The Builder pattern very often addresses the process of translating forms. My recent case was a good example of this: someone stating a preference is not generally providing all the details that are needed to then construct the objects needed to honor that preference. For instance, suppose I tell you that I am on the South Beach Diet. That is a preference, but for me to make any use of that information, I need to create other constructs. This is a classic Builder application: the foreign form (the preference) is just a way to signal certain rules and behaviors. In this way, Builder looks like a way to guide the construction process with indicators from outside.
The example in the Gang of Four starts with the RTF reader, which is pretty straightforward, one-way transformation where the original form is discarded, then goes into that whacky maze-building stuff. There are probably a small set of ways that Builder is generally applied. Breaking those down would probably be interesting… (I have been thinking about doing a set of super cheap books on some of the key design patterns and self-publishing them really cheaply on Kindle/iBooks. Does a whole book on Builder or Prototype seem insane? Not to me.. but then…) The cool thing about builder is that interesting combinations could be shown, e.g. collecting preferences from the User but also injecting intelligence that had been gathered from all users at one time using two builders that are intertwined.
One of the most common mistakes you hear from people when they talk about design patterns is they think Factory is a DP. An Abstract Factory is, a Factory Method is, but Factory itself is not. Factories probably outnumber Builders out there 100:1. I‘d like to go trolling through them and see how many of them get rapidly gunked up with procedural goo and defy any kind of intermediation or extension. Betting that‘s the rule.