The builder pattern and a large number of mandatory parameters

speedRS picture speedRS · Sep 5, 2011 · Viewed 39.1k times · Source

To date I use the following implementation of the builder pattern (as opposed to the implementation described here):

public class Widget {
    public static class Builder {
        public Builder(String name, double price) { ... }
        public Widget build() { ... }
        public Builder manufacturer(String value) { ... }
        public Builder serialNumber(String value) { ... }
        public Builder model(String value) { ... }
    }

    private Widget(Builder builder) { ... }
}

This works well for most situations I've encountered where I need to build up a complex object with a variety of required/mandatory and optional parameters. However, I've been struggling lately to understand how the pattern is of any benefit when all your parameters are mandatory (or at least the vast majority are).

One means of getting around this has been to logically group the parameters being passed in to their own classes to reduce the number of parameters being passed to the builder constructor.

For example, instead of:

Widget example = new Widget.Builder(req1, req2, req3,req4,req5,req6,req7,req8)
                           .addOptional(opt9)
                           .build();

becomes grouped as follows:

Object1 group1 = new Object1(req1, req2, req3, req4);
Object2 group2 = new Object2(req5, req6);

Widget example2 = new Widget.Builder(group1, group2, req7, req8)
                            .addOptional(opt9)
                            .build();

While having separate objects simplifies things quite a bit, it also makes things a little difficult to follow if one is not familiar with the code. One thing I considered was moving all parameters into their own addParam(param) methods and then performing validation on required parameters in the build() method.

What is best practice and is there perhaps a better approach to this that I haven't considered?

Answer

deamon picture deamon · Mar 7, 2016

You can use a Step Builder if you have many mandatory parameters. In short: you define an interface for every single mandatory parameter and a builder method returns the next mandatory builder interface or the builder itself for optional methods. The builder remains a single class which implements all the interfaces.

Languages like Kotlin and Scala are more convenient here, since they offer named parameters with default values.