Builder

Builder Pattern

Introduction

The Builder pattern is a creational design pattern that separates the construction of a complex object from its representation. This pattern is particularly useful when an object needs to be created with many possible configurations and constructing such an object is a complex process.

Purpose

  • To separate the construction of a complex object from its representation.
  • To allow the same construction process to create various representations.

Use Cases

  • When the algorithm for creating a complex object should be independent of the parts that make up the object and how they’re assembled.
  • When the construction process must allow different representations for the object that’s constructed.

Advantages/Disadvantages

Advantages:

  • Provides control over the construction process.
  • Supports varying the internal representation of products.
  • Isolates complex construction code from the business logic of the product.

Disadvantages:

  • Can increase the overall complexity of the code by adding multiple additional classes.

Implementation in JavaScript

javascript
	class Builder {
	  buildPartA() {}
	  buildPartB() {}
	  getResult() {}
	}
	
	class ConcreteBuilder extends Builder {
	  constructor() {
	    super();
	    this.product = new Product();
	  }
	
	  buildPartA() {
	    this.product.add('PartA');
	  }
	
	  buildPartB() {
	    this.product.add('PartB');
	  }
	
	  getResult() {
	    return this.product;
	  }
	}
	
	class Product {
	  constructor() {
	    this.parts = [];
	  }
	
	  add(part) {
	    this.parts.push(part);
	  }
	}
	
	// Usage
	const builder = new ConcreteBuilder();
	builder.buildPartA();
	builder.buildPartB();
	const product = builder.getResult();
	
	console.log(product); // Product with parts ['PartA', 'PartB']

Practical Example

Imagine we’re building a system for generating reports in different formats (e.g., JSON, XML). We’ll use the Builder pattern to construct various types of reports.

javascript
	class ReportBuilder {
	  setHeader() {}
	  setContent() {}
	  setFooter() {}
	  getReport() {}
	}
	
	class JSONReportBuilder extends ReportBuilder {
	  constructor() {
	    super();
	    this.report = { header: '', content: '', footer: '' };
	  }
	
	  setHeader(header) {
	    this.report.header = header;
	  }
	
	  setContent(content) {
	    this.report.content = content;
	  }
	
	  setFooter(footer) {
	    this.report.footer = footer;
	  }
	
	  getReport() {
	    return JSON.stringify(this.report);
	  }
	}
	
	class XMLReportBuilder extends ReportBuilder {
	  constructor() {
	    super();
	    this.report = '<report>';
	  }
	
	  setHeader(header) {
	    this.report += `<header>${header}</header>`;
	  }
	
	  setContent(content) {
	    this.report += `<content>${content}</content>`;
	  }
	
	  setFooter(footer) {
	    this.report += `<footer>${footer}</footer>`;
	  }
	
	  getReport() {
	    return this.report + '</report>';
	  }
	}
	
	// Usage
	const jsonBuilder = new JSONReportBuilder();
	jsonBuilder.setHeader('JSON Report Header');
	jsonBuilder.setContent('This is the content');
	jsonBuilder.setFooter('JSON Report Footer');
	const jsonReport = jsonBuilder.getReport();
	
	const xmlBuilder = new XMLReportBuilder();
	xmlBuilder.setHeader('XML Report Header');
	xmlBuilder.setContent('This is the content');
	xmlBuilder.setFooter('XML Report Footer');
	const xmlReport = xmlBuilder.getReport();
	
	console.log(jsonReport); // JSON formatted report
	console.log(xmlReport); // XML formatted report

In this practical example, the JSONReportBuilder and XMLReportBuilder classes implement the ReportBuilder interface to build reports in JSON and XML formats, respectively. This demonstrates how the Builder pattern can be used to construct complex objects step-by-step.