3

I am currently learning about various object oriented design patterns. I came across a pattern called the builder pattern which is basically where you build a complex object through the use of creating simple objects that build on each other step by step.

My question is, in what scenarios would such a design pattern be appropriate? Which kind of tasks would benefit from such a design pattern?

5

Whenever creation of new object requires setting many parameters and some of them (or all of them) are optional.

E.g. (for Java but you can easily transform to other language)

User.builder()
       .name("John")
       .age(30)
       .sex(Sex.MALE)
       .build()

instead of

User user = new User();

user.setName("John");
user.setAge(30); 
...

You can also create easily objects for test with such a builder e.g.

User maleUserOver30() {
   return User.builder()
                 .sex(Sex.MALE)
                 .age(31)
                 .build();
} 
  • 2
    This is called Bloch Builder. It's NOT a design pattern of GoF at all. – Niing Apr 7 '17 at 1:02
  • 1
    This answer will cause more people mis-understand what actually called a Design Pattern. – Niing Apr 7 '17 at 1:03
  • @N1ng Read the question once again and then comment. You don't know what you're talking about - I am quite curious who upvoted your comments. – Tomasz Maciejewski Apr 7 '17 at 11:31
  • 1.Builder pattern from wiki, which is what OP want to know. 2.You answer is about Fluent interface 3. Notice that even in wiki, the builder pattern is implemented by the way you said instead of. 4. Read this post about the differences between Bloch Builder and Builder Pattern of GoF. 5. Don't care too much about people's votes, that means nothing. 6. Sorry to make you feel bad. – Niing Apr 7 '17 at 14:09
  • @N1ng I don't want to extend this discussion but I don't understand your arguments at all. The way I presented the builder pattern is the way it should be used in current moment - having a lot of benefits. The GoF book is neither a oracle not a up-to-date book. The same with wiki. And so called Bloch Builder is correct implementation of Builder pattern from GoF (think about it!). And about the post you mentioned - nothing spectacular there. – Tomasz Maciejewski Apr 7 '17 at 14:54
5

To start I'll quickly contrast with the Factory Pattern. Both are used to abstract elements of object creation, however a factory pattern is most appropriate where the actual type of returned object is not known until runtime. If the type of the required object is known at design-time, I find factories to be inappropriate more often than not. However, the builder pattern is appropriate for single-type class creating, and many factories can encompass some elements of the builder pattern.

Where the builder pattern is most useful is when you are dealing with a situation where:

There are enough data fields that having them all in the constructor(s) is obnoxious, but you need the object to always be in a valid state.

The most obvious example is for immutable data types. If you have some data class that has dozens of properties/fields, especially if some of them optional, then putting all those in the constructor is going to be super annoying. On the otherhand, if you want that class to be immutable, you cannot instantiate an instance then modify a handful of properties. There are workarounds where you have a 'lock' method which afterwards makes properties read only, but that's annoying too. A builder is a good solution to the problem.

Similarly the builder that provide error checking/validation, or can provide alternative interfaces to the internal fields of the class, such as providing means to specify imperial or metric units or some such.

Even if the class is mutable, the builder pattern can still provide a means to make sure the class starts its life in a valid state, and the property updating methods can be used to maintain that validity as things are updated.

If you have mutable classes that only have to be in a valid state some of the time, such as a GUI widget that only has to be valid when the window is drawn, the builder pattern can lose a lot of its utility in those situations.

2

What I haven't seen mentioned in the answers above is the following. Using the builder pattern makes for cleaner code.

Cleaner code

Say you've created a library which exposes a POJO that's essential to the function of your library. The constructor of that POJO has one or two parameters which are essential. Now for a new feature that POJO needs another field that is essential. If you're not using the builder pattern you will need to add another parameter to the POJO's constructor.

Constructor nesting

To maintain backwards compatibility you will probably add a second constructor with three parameters and have the first constructor call the second constructor with some default value for the third parameter.

Something along the lines of:

constructor1(x,y){constructor2(x,y, "default")}

If you add a parameter a few times you will have a bunch of constructors you will need to maintain, have reduced the readability of your code and it makes for a confusing interface to someone who is new to your code-base.

Be gone constructor nesting!

If you use a builder, each time you want to add a parameter to the constructor, you simply add a method for said parameter and you're done. No clutter, easy to maintain and since it follows a specific pattern a new team-member will get the gist of it quite fast.

Don't use it for clean-code alone

Of course this doesn't apply when you don't expect the constructor to change. Which is quite the assumption but it's possible. So I would suggest that you look at the reasoning mentioned in the other answers first when you're considering the builder pattern.

Builder pattern as a sign of over-responsibility

Most likely if you're using the Builder pattern you've got a large amount of fields in your class. Meaning you may have added to much responsibility to that particular class. So you could also consider looking at the parameters you're passing. Whether you use a few of them in conjunction and if you do, create a new class that's responsible for handling any behaviour associated with those parameters. Then simply remove those parameters from the constructor and pass an instance of the new class to your original class [1] . There are down-sides to this but at least you've cleaned up your code and avoided introducing the Builder pattern needlessly.

TL:DR;

  1. The builder-pattern cleans up your code by eliminating the need for constructor-nesting.
  2. See if you can't introduce a parameter object before you introduce the builder pattern [1]. As wanting to introduce the builder pattern may be a sign of to much responsibility in one class.
  3. Don't introduce it just because "it's cleaner". It is. However, a constructor can be just as effective.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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