Master java skills

Builder Design Pattern

Builder design pattern is used to build a complex object using step-by-step approach.

Assume there is a class with many attributes. Below are the challenges in creating the object of such a class.

Challenges without builder pattern

  1. Obviously not all of them will be mandatory ones. Some of them will be mandatory and others will be optional. So, if you go by all parameters constructor, then even if someone doesn’t need a parameter, they are bound to pass some value because the constructor needs it.
  2. If you go with multiple constructors approach, there can be n number of permutations and combinations.
  3. Also, the constructors will be verbose and clumsy from readability point of view.

As a solution to all the above problems the Builder design pattern comes to the rescue. It says that, in the first step, create the object initializing the mandatory parameters and then give option to set the optional parameters. So, the user can first create the object with mandatory parameters and then set as many optional ones as required.

Here we will take example of making Subway style salad. Subway is a chain of restaurant famous for giving the customers flexibility to customize the order of the same item to a great extent. You can choose your own ingredients and sauces from given options. Here, builder pattern will be used. A basic salad will be built using necessary ingredients with options to further customize it.

Important points to remember while implementing builder pattern

  1. Identify the mandatory and optional parameters in the class whose object you want to build using builder pattern.
  2. Write a public static inner class with name as <outer-class-name>Builder, e.g if we have a class called Car, then inner class name will be CarBuilder
  3. In this inner class keep all the properties of the outer class. Have a constructor of this inner class that has only mandatory parameters.
  4. Have setter methods of the optional parameters. Please make sure that every setter method returns the object of the inner class only.
  5. Write a build method inside the builder class that returns the outer class’ object.
  6. Write a private constructor of the original (outer) class that takes Builder object and initializes all its properties from the builder object’s properties.

Salad.java

package com.sks.builder;

import java.util.List;

public class Salad {
		
	//mandatory parameters
	private String name;
	private String saladSize;
	private List<String> mandatoryItems;
	
	//optional parameters
	private List<String> saladSauces;
	private boolean ispickleNeeded;
	private boolean isJalpenosNeeded;
	private boolean isSeasoningNeeded;
	private boolean isSaltPepperNeeded;
	private List<String> extraItems;
	
	private Salad(SaladBuilder builder) {
		this.name = builder.name;
		this.saladSize = builder.saladSize;
		this.mandatoryItems = builder.primaryVegetables;
		this.saladSauces = builder.saladSauces;
		this.ispickleNeeded = builder.ispickleNeeded;
		this.isJalpenosNeeded = builder.isJalpenosNeeded;
		this.isSeasoningNeeded = builder.isSeasoningNeeded;
		this.isSaltPepperNeeded = builder.isSaltPepperNeeded;
		this.extraItems = builder.extraItems;
	}
	
	//static inner class
	public static class SaladBuilder {
		
		//mandatory parameters
		private String name;
		private String saladSize;
		private List<String> primaryVegetables;
		
		
		//optional parameters
		private List<String> saladSauces;
		private boolean ispickleNeeded;
		private boolean isJalpenosNeeded;
		private boolean isSeasoningNeeded;
		private boolean isSaltPepperNeeded;
		private List<String> extraItems;
		
		//constructor with mandatory parameters
		public SaladBuilder(String name, String saladSize, List<String> primaryVegetables) {
			super();
			this.name = name;
			this.saladSize = saladSize;
			this.primaryVegetables = primaryVegetables;
		}
		
		public Salad build() {
			return new Salad(this);
		}

		public SaladBuilder setSaladSauces(List<String> saladSauces) {
			this.saladSauces = saladSauces;
			return this;
		}
		
		public SaladBuilder setIspickleNeeded(boolean ispickleNeeded) {
			this.ispickleNeeded = ispickleNeeded;
			return this;
		}

		public SaladBuilder setJalpenosNeeded(boolean isJalpenosNeeded) {
			this.isJalpenosNeeded = isJalpenosNeeded;
			return this;
		}

		public SaladBuilder setSeasoningNeeded(boolean isSeasoningNeeded) {
			this.isSeasoningNeeded = isSeasoningNeeded;
			return this;
		}

		public SaladBuilder setSaltPepperNeeded(boolean isSaltPepperNeeded) {
			this.isSaltPepperNeeded = isSaltPepperNeeded;
			return this;
		}

		public SaladBuilder setExtraItems(List<String> extraItems) {
			this.extraItems = extraItems;
			return this;
		}
	}

	public String getName() {
		return name;
	}

	public String getSaladSize() {
		return saladSize;
	}

	public List<String> getPrimaryVegetables() {
		return mandatoryItems;
	}

	public List<String> getSaladSauces() {
		return saladSauces;
	}

	public boolean isIspickleNeeded() {
		return ispickleNeeded;
	}

	public boolean isJalpenosNeeded() {
		return isJalpenosNeeded;
	}

	public boolean isSeasoningNeeded() {
		return isSeasoningNeeded;
	}

	public boolean isSaltPepperNeeded() {
		return isSaltPepperNeeded;
	}

	public List<String> getExtraItems() {
		return extraItems;
	}

	@Override
	public String toString() {
		return "Salad [name=" + name + ", saladSize=" + saladSize + ", mandatoryItems=" + mandatoryItems
				+ ", saladSauces=" + saladSauces + ", ispickleNeeded=" + ispickleNeeded + ", isJalpenosNeeded="
				+ isJalpenosNeeded + ", isSeasoningNeeded=" + isSeasoningNeeded + ", isSaltPepperNeeded="
				+ isSaltPepperNeeded + ", extraItems=" + extraItems + "]";
	}
}

Test class

package com.sks.builder;

import java.util.Arrays;
import java.util.List;


public class BuilderPatternTest {

	public static void main(String[] args) {
		
		List<String> primaryItems = Arrays.asList("Paneer", "Tomato", "Capcicum",
				"Lettuce");
		//make a plain salad without any additional items or sauces
		Salad s = new Salad.SaladBuilder("Paneer Tikka Salad", "Large", primaryItems).build();
		
		System.out.println(s);
		
		//Now let's customize this salad. Add some sauces, cutlery, seasoning
		List<String> saladSauces = Arrays.asList("Barbeque", "Southwest Chipotle");
		Salad s1 = new Salad.SaladBuilder("Paneer Tikka Salad", "Regular", primaryItems).
				setSaladSauces(saladSauces).setExtraItems(Arrays.asList("Cutlery")).setSeasoningNeeded(true)
				.setJalpenosNeeded(true).build();
		
		System.out.println(s1);
	}	
}

Output:

Now, that you have made a salad using Builder Pattern. You deserve one. Eat healthy, think healthy.