Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The builder pattern and a large number of mandatory parameters

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?

like image 338
speedRS Avatar asked Sep 05 '11 00:09

speedRS


People also ask

Which type of design pattern is builder pattern?

Builder pattern builds a complex object using simple objects and using a step by step approach. This type of design pattern comes under creational pattern as this pattern provides one of the best ways to create an object. A Builder class builds the final object step by step.

What is builder pattern?

The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation. It is one of the Gang of Four design patterns.

How do you avoid too many parameters in a constructor?

Using a builder can solve the issue of having to many parameters in a constructor when all the fields are not mandatory. It also takes away the problems with having multiple constructors for different purposes. Note that a builder still should have a constructor with the mandatory fields that always needs to be set.

What is builder factory design pattern?

Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.” It is used to construct a complex object step by step and the final step will return the object.


1 Answers

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 c StepBuilder.with().a("hello").b("world").c("!").build(); 

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

like image 132
deamon Avatar answered Sep 20 '22 14:09

deamon