The builder pattern and a large number of mandatory parameters The builder pattern and a large number of mandatory parameters java java

The builder pattern and a large number of mandatory parameters


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.

interface StepB {    StepBuilder b(String b);}interface StepA {    StepB a(String a);}final class StepBuilder implements StepA, StepB {    private String a;    private String b;    private String c = "";    private StepBuilder() {    }    static StepA with() {      return new StepBuilder();    }    // mandatory, from StepA    @Override    StepB a(String a) {        this.a = a;        return this;    }    // mandatory, from StepB    @Override    StepBuilder b(String b) {        this.b = b;        return this;    }    // optional    StepBuilder c(String c) {        this.c = c;        return this;    }    Product build() {        return new Product(a, b, c);    }}

Usage:

StepBuilder.with().a("hello").b("world").build();// or with the optional parameter cStepBuilder.with().a("hello").b("world").c("!").build();

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


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).

The fluent builder pattern is still beneficial:

  1. Its more readable - it effectively allows named parameters so that the call isn't just a long list of unnamed arguments

  2. Its unordered - this lets you group arguments together into logical groups, either as part of a single builder setter call or simply by letting you use a natural order to calling the builder setter methods that make the most sense of this particular instantiation.


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.

I would favor a hybrid when appropriate or natural. It doesn't have to be all in constructor or each param has its own addParam method. Builder gives you flexibility to do one, the other, in-between, or a combo:

Widget.Builder builder = new Widget.Builder(Widget.BUTTON);builder.withWidgetBackingService(url, resource, id);builder.withWidgetStyle(bgColor, lineWidth, fontStyle);builder.withMouseover("Not required");Widget example = builder.build();


I've been struggling lately to understand how the pattern is of any benefit when all your parameters are mandatory

The pattern eases creation of immutable classes and promotes readable code. Consider the Person class below (with a conventional constructor and a builder).

public static class Person {    private static final class Builder {        private int height, weight, age, income, rank;        public Builder setHeight(final int height) { this.height = height; return this; }        public Builder setWeight(final int weight) { this.weight = weight; return this; }        public Builder setAge(final int age) { this.age = age; return this; }        public Builder setIncome(final int income) {    this.income = income; return this; }        public Builder setRank(final int rank) { this.rank = rank; return this; }        public Person build() { return new Person(this); }    }    private final int height;    private final int weight;    private final int age;    private final int income;    private final int rank;    public Person(final int height, final int weight, final int age, final int income, final int rank) {        this.height = height; this.weight = weight; this.age = age; this.income = income; this.rank = rank;    }    private Person(final Builder builder) {        height = builder.height; weight = builder.weight; age = builder.age; income = builder.income; rank = builder.rank;        // Perform validation    }    public int getHeight() { return height; }    public int getWeight() { return weight; }    public int getAge() { return age; }    public int getIncome() { return income; }    public int getRank() {  return rank; }}

Which method of construction is easier to comprehend?

final Person p1 = new Person(163, 184, 48, 15000, 23);final Person p2 = new Person.Builder().setHeight(163).setWeight(184).setAge(48).    setIncome(15000).setRank(23).build();

One means of getting around this has been to logically group the parameters being passed in to their own classes

Sure, this is the principle of cohesion and should be adopted irrespective of object construction semantics.