Question

The book Design Patterns: Elements of Reusable Object-Oriented Software says to use the builder pattern when

  1. The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled.

  2. The construction process must allow different representations for the object that's constructed.

I got the second point which in simple terms I think translates to just avoid having too many constructors.

The first half of first point deals with shifting of object creation process to another class.

The later half talking about assembling is not clear to me. I would like to know of any real world example where we shouldn't implement builder pattern when The algorithm for creating a complex object should is dependent of how the parts that make up the object are assembled.

Was it helpful?

Solution

This is a misunderstanding of the builder pattern. The whole purpose of the pattern is to decouple the building process from the concrete classes that are built. Let's have a second reading:

  1. The construction process must allow different representations for the object that's constructed.

This is not about having many constructors or not. The terms "construction process" and "object constructed" refer in fact to the "building process" and "the object being build". This is an English language ambiguity.

The key in that sentence is rather different representations. This means that the building process must be independent of the implementation of the classes involved, and should solely depend on their interfaces.

  1. The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled.

Indeed, the independence implies in many OOP languages shifting of object creation process to another class. Theoretically, you could also think of a free-standing function in some languages, but in practice this would often not be sufficient.

The part about the assembling is key. THe idea is that the builder is used to construct complex objects. "Complex" means "made of many parts" (not to be confused with complicated, i.e. difficult to understand). So often you have to create the parts (sub-objects, components, ...), and then in the end "assemble the parts": this is often done by calling a constructor with the parts as parameters. Alternatively, it could also be done, constructing the final object, and invoke its interface to add its parts.

Caution: One frequent source of confusion is that there are two popular builder patterns: the GoF pattern (examined above) and Bloch's pattern (which is used in Java when constructors have many parameters). Unfortunately, the identical naming cause many people to believe it's the same pattern. There are quite a lot of blogs that pretend to explain GoF builder pattern, but with code corresponding to Bloch's pattern. There are also quite some that seem to think it's the same pattern and try to draw a mapping. These patterns are related, have some similarities, but are not the same and address different problems.

OTHER TIPS

This is one of the least understood and least used patterns from GoF. It's hard to find a good example of it in real use. And as Christophe has pointed out, Bloch's Builder having the same name has only made things worse. I think it's one of the most powerful patterns, however and it's worth understanding. I haven't had many opportunities to use it in my work but I have used it to good effect once or twice. I think an example helps greatly.

Consider a situation where you have a complex data structure. Maybe it's in a DB with many related tables or maybe it's in a hierarchical structure, it doesn't really matter. Now you are given the task of generating a graphical interface for this data and multiple output formats. What most people end up doing is creating some sort of class structure that represents the data and then have multiple sets of code that traverse it. This has one big drawback in that the traversal code is tightly coupled to the data structure but also coupled to the structure of the output. So for N outputs, you need N traversals. This is bad but now let's say you also have M data structures that you need to map to these N formats. Now you have M times N traversal procedures to worry about. This pattern is helpful in situations like that.

Effectively you separate the traversal from the output format. Now you just have M traversal procedures to worry about. But now you need to get these to each produce N outputs. That's where the trick is. You create an abstraction on top of all the outputs that encompasses all the distinct 'rendering' options. For example, if you need encounter a nested object, you no longer write out an HTML node or a create a new widget or add a nested JSON element directly. You simple tell the abstraction that a new child has been encountered and it's properties. Then your various implementations of that abstraction do whatever they do when a child is encountered. This isn't the easiest thing to accomplish but when you get it right, it's can really make things a lot simpler over all, if you have this kind of need.

Licensed under: CC-BY-SA with attribution
scroll top