Sobes.tech
Middle

Tell us about the 'Builder' design pattern.

sobes.tech AI

Answer from AI

The "Builder" design pattern is a creational pattern that allows for step-by-step construction of complex objects. It separates the construction process of a complex object from its representation, so that the same construction process can create different representations.

Main components:

  • Builder: An interface or abstract class defining methods for creating parts of a complex object.
  • Concrete Builder: Implements the Builder interface and provides specific implementations for building parts of the object. It stores intermediate results and provides a method to retrieve the finished object.
  • Director: An optional component that defines the order of calling builder methods to create the object. It does not know about the specific builders.
  • Product: The complex object that is created by the builder.

Application:

  • When the process of creating an object is complex and involves many optional steps.
  • When it is necessary to create different representations of the same object using the same construction process.
  • When the constructor of the object has many parameters.

Example in Go:

// Product - complex object
type Product struct {
	PartA string
	PartB string
	PartC string
}

// Builder - interface for builder
type Builder interface {
	BuildPartA()
	BuildPartB()
	BuildPartC()
	GetProduct() *Product
}

// ConcreteBuilder - specific builder
type ConcreteBuilder struct {
	product *Product
}

func NewConcreteBuilder() *ConcreteBuilder {
	return &ConcreteBuilder{product: &Product{}}
}

func (cb *ConcreteBuilder) BuildPartA() {
	cb.product.PartA = "Part A built"
}

func (cb *ConcreteBuilder) BuildPartB() {
	cb.product.PartB = "Part B built"
}

func (cb *ConcreteBuilder) BuildPartC() {
	cb.product.PartC = "Part C built"
}

func (cb *ConcreteBuilder) GetProduct() *Product {
	return cb.product
}

// Director - optional
type Director struct {
	builder Builder
}

func NewDirector(builder Builder) *Director {
	return &Director{builder: builder}
}

func (d *Director) Construct() {
	d.builder.BuildPartA()
	d.builder.BuildPartB()
	d.builder.BuildPartC()
}

// Usage
// concreteBuilder := NewConcreteBuilder()
// director := NewDirector(concreteBuilder)
// director.Construct()
// product := concreteBuilder.GetProduct()
// fmt.Printf("Product created: %+v\n", product)

Advantages:

  • Isolates the object construction code from its client code.
  • Allows changing the internal representation of the product without changing client code.
  • Enables step-by-step construction of the object.
  • Simplifies creation of objects with many parameters.

Disadvantages:

  • Increases the amount of code (classes/interfaces) for object creation.
  • May be redundant for simple objects.