20

When using a language that supports named and optional arguments, does the builder pattern no longer have a practical use?

Builder:

new Builder(requiredA, requiredB).setOptionalA("optional").Build();

Optional/named arguments:

new Object(requiredA, requiredB, optionalA: "optional");
  • 3
    How do you handle 20 optional arguments? There isn't a problem the Builder needs to solve until it gets large. At the point you've described here you've got two constructors (and I wouldn't build a Builder for that small of a problem). – user40980 Apr 24 '15 at 19:29
  • 1
    Even with optional arguments - if the constructor has more than 2 arguments, I favour using a value object to encapsulate configuration. The same goes for fluid inerfaces and builder: Anything greater than 3 would be substituted by a value object. – Thomas Junk Apr 30 '15 at 23:35
21

Builders are most useful when your object needs a lot of arguments/dependencies to be useful, or you want to allow many different ways of constructing the object.

Off the top of my head, I can imagine someone might want to "build" objects in a 3D game like this:

// Just ignore the fact that this hypothetical god class is coupled to everything ever
new ObjectBuilder(x, y, z).importBlenderMesh("./meshes/foo")
                          .syncWithOtherPlayers(serverIP)
                          .compileShaders("./shaders/foo.vert", "./shaders/foo.frag")
                          .makeDestructibleRigidBody(health, weight)
                          ...

I would argue this example is more readable with the builder methods I made up just now than it would be with optional parameters:

new Object(x, y, z, meshType: MESH.BLENDER,
                    meshPath: "./meshes/foo",
                    serverToSyncWith: serverIP,
                    vertexShader: "./shaders/foo.vert",
                    physicsType: PHYSICS_ENGINE.RIGID_DESTRUCTIBLE,
                    health: health,
                    weight: weight)
                    ...

In particular, the information implied by the builder method names has to get replaced by yet more parameters, and it's much easier to forget about one parameter in a group of closely related parameters. In fact, the fragment shader is missing, but you wouldn't notice that unless you knew to look for it.


Of course, if your object only takes one to five arguments to construct, there's no need to get the builder pattern involved, whether or not you have named/optional parameters.

  • I don't buy your arguments. If the builder method names are so wonderful, you can use them as well for the parameter names. If parameters are closely related, put them into a small object constructor. – user949300 Mar 20 '17 at 5:48
  • @user949300 I think you've missed the important part of the point, which is that the builder methods here describe relationships between the parameters that get lost if you just have a bunch of optional parameters. In Ixrec's builder example, "health" and "weight" are clearly logically part of the destructible body settings, but that relationship get l gets lost in the optional argument version. – Jules Mar 20 '17 at 8:42
  • 1
    not if one of the optional parameters is (body: new DestructibleRigidBody(health, weight), ...) – Weyland Yutani Mar 20 '17 at 9:39
  • @Jules. What Weyland said - make a little well-named constructor for weight & height. – user949300 Mar 20 '17 at 15:08
8

In addition to what Ixrec said, the constructors or method named parameters won't allow you to have your object in a to-be-constructed state in which it can still be modified before building it. This is the beauty of the Builder, where you can delegate parts of its construction to different methods or classes altgether:

var myThingBuilder = new ThingBuilder("table");
myThingBuilder.setAttribute(Attributes.Legs, 4);

inventoryManager.setPrices(myThingBuilder);

// inventory manager
var availableCheapestMaterial = getMaterial();
myThingBuilder.setMaterial(availableCheapestMaterial);

Basically, you're also able to throw your builder around your system until it is ready to build the final object, allowing you to decrease the amount of knowledge that your builder-consumer needs to have.

  • I don't understand your last paragraph. If you "throw your builder around the system until it is ready", it has far too much knowledge of the system. Your ThingBuilder knows about Attributes, is mysteriously modified by InventoryManager, and knows about Materials. Don't see how that is decreasing knowledge. – user949300 Mar 20 '17 at 5:55
  • @user949300 Think of how it would be without the builder traveling across the system. You'd be forced to have a class with a huge fan-out factor, and that is just necessary to build the Thing. (Of course, assuming your class doesn't concentrate all the knowledge, this is what we wanted to avoid in the first place.) Now, if this class has any other responsibility, you're creating a huge class, breaking S in SOLID. If that's the only responsibility, you're making yourself a ThingBuilder. – Alpha Mar 20 '17 at 9:16
1

It depends on what you are doing with the builder.

If you are using builder just to set (and vary) object properties and (defer) object creation, it can be replaced with named params.

Replacing the builder you may have the readability/usage tradeoff that @Ixrec mentoned (or may not have it, it depends on what you are doing with the builder).

However, if your builder does more than just holding the properties and each construction step involves logic, it can't be replaced.

MockBuilder is an example where it can't be replaced with named params. From the page:

Logic on creation steps cannot be replaced with named params

-5

The builder pattern is essential when working with immutable objects. There are a lot of benefits working with immutable objects, especially in making your program be more robust executing in a concurrent environment (i.e., threads)

  • 3
    Yes, Builders are great for working with complex immutable objects (or even mutable ones - you need to make sure that the object is in a consistent state before it can be used). That said, new Integer(42), new BigDecimal("42.000") and new String("foobar") are all constructors to immutables that... well, a builder would be needlessly complex for these instances. So a builder isn't essential for working with immutable when constructors can work just as well. – user40980 Apr 30 '15 at 22:00
  • Yes, a constructor can be used with immutable objects, that is not being denied. But the original question was whether the Builder pattern has any practical use apart from the optional arguments and my response was to clarify this. – codedabbler Apr 30 '15 at 22:05
  • 2
    The original question says nothing about immutable objects. It is asking about named parameters and the relationship to them with Builders. Your answer is about the builder and its relationship to immutable objects. I have a hard time seeing how your answer answers the question. – user40980 Apr 30 '15 at 22:07

protected by gnat Mar 18 '17 at 17:44

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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