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");
2
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.
5
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.
2
It depends on what you are doing with the builder.
If you use builder just to set (and vary) object properties and (defer) object creation, it can be replaced with named params (if available for the language).
Replacing the builder, you may have the readability/usage tradeoff that @Ixrec mentioned (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:
1
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