5

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.

2 Answers 2

4

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.

4
  • For an OO language, your definition of 'different representations' I guess means that the class acting as concrete builder should only interact with the fields of the object through their interfaces to build them. But still this doesn't answer what 'different representations' mean. If it mean different representations of the object then how can an object have different representations other than having different field values ? Feb 28, 2021 at 12:14
  • 1
    @NishantIngle if I understood this right, a good example coming from my current project: I've got two different types of servers, performing same tasks buy with different communication schemes. Internally these are two different concrete classes implementing the same interface. With GoF builder I'll pass it the config data and get an object implementing that interface without caring about the particular implementation.
    – jaskij
    Feb 28, 2021 at 12:39
  • @NishantIngle indeed, Jan example is right. In the GoF the example is a text converter (builder) that is invoked by an RTF document-reader application to build ascii, TeX and other formats (today they’d probably add html and xml) documents. These are all different representations of the initial RTF text (maybe loosing or transposing some formatting), encapsulated in different classes. Adding a new converter to a new format (say json) just requires a new concrete builder that would follow the same building process but using the the new types needed.
    – Christophe
    Feb 28, 2021 at 14:15
  • @Christophe maybe would be best to incorporate an example in the answer? SE comments are quite volatile.
    – jaskij
    Mar 2, 2021 at 9:32
0

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.

1
  • I don't have time to create an actual example at the moment but if this answer is not sufficient, I can put something simple together for you to demonstrate the approach but probably not large enough to demonstrate the applicability.
    – JimmyJames
    Mar 1, 2021 at 21:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.