DEV Community

Kittipat.po
Kittipat.po

Posted on • Edited on

Understanding the Builder Pattern in Go

Builder Pattern

The Builder Pattern is a creational design pattern that provides an abstraction over object construction. Instead of directly constructing an object with a large number of constructor arguments, the pattern splits the construction process into multiple smaller steps. Each step is handled by a separate builder, which allows for greater flexibility and configurability.

The key components of the Builder Pattern are:

  • Product: Represents the complex object being built.
  • Builder: Provides an interface for constructing the parts of the product.
  • Concrete Builder: Implements the builder interface and constructs the parts of the product.
  • Director: Orchestrates the construction process by using the builder interface.

Implementing the Builder Pattern in Go

Let's now dive into a practical example of how to implement the Builder Pattern in Go. We'll create a CarBuilder that allows users to build customized cars with various options. The car can have attributes such as color, engine type, and optional accessories like sunroofs and navigation systems.

package main

// Car represents the complex object being built.
type Car struct {
    color         string
    engineType    string
    hasSunroof    bool
    hasNavigation bool
}

// CarBuilder provides an interface for constructing the parts of the car.
type CarBuilder interface {
    SetColor(color string) CarBuilder
    SetEngineType(engineType string) CarBuilder
    SetSunroof(hasSunroof bool) CarBuilder
    SetNavigation(hasNavigation bool) CarBuilder
    Build() *Car
}

// NewCarBuilder creates a new CarBuilder.
func NewCarBuilder() CarBuilder {
    return &carBuilder{
        car: &Car{}, // Initialize the car attribute
    }
}

// carBuilder implements the CarBuilder interface.
type carBuilder struct {
    car *Car
}

func (cb *carBuilder) SetColor(color string) CarBuilder {
    cb.car.color = color
    return cb
}

func (cb *carBuilder) SetEngineType(engineType string) CarBuilder {
    cb.car.engineType = engineType
    return cb
}

func (cb *carBuilder) SetSunroof(hasSunroof bool) CarBuilder {
    cb.car.hasSunroof = hasSunroof
    return cb
}

func (cb *carBuilder) SetNavigation(hasNavigation bool) CarBuilder {
    cb.car.hasNavigation = hasNavigation
    return cb
}

func (cb *carBuilder) Build() *Car {
    return cb.car
}

// Director provides an interface to build cars.
type Director struct {
    builder CarBuilder
}

func (d *Director) ConstructCar(color, engineType string, hasSunroof, hasNavigation bool) *Car {
    d.builder.SetColor(color).
        SetEngineType(engineType).
        SetSunroof(hasSunroof).
        SetNavigation(hasNavigation)

    return d.builder.Build()
}

func main() {
    // Create a new car builder.
    builder := NewCarBuilder()

    // Create a car with the director.
    director := &Director{builder: builder}
    myCar := director.ConstructCar("blue", "electric", true, true)

    // Use the car object with the chosen configuration.
    // ...
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define the Car struct, which represents the complex object we want to build. The CarBuilder interface provides methods to configure different parts of the car, and the carBuilder type implements the interface.

The Director struct orchestrates the construction process and delegates the building tasks to the concrete builder (carBuilder). The client code can use the Director to construct a car with various options without being concerned about the construction details.

Conclusion 🥂

The Builder Pattern is a powerful design pattern that simplifies the construction of complex objects with multiple configuration options. By splitting the construction process into smaller steps, the pattern promotes code reusability, maintainability, and flexibility.

Top comments (2)

Collapse
 
amermelao profile image
amermelao

Hi there,

The example is very good. There is only one issue. The car attribute in carBuilder is a pointer and it is not being initialize.

Best Regard,

A.

Collapse
 
ritu_raj_a03954d6267dc89d profile image
RITU RAJ

I have a q uery..why not assign all those values in one call
like cb.Car.X = sth,
cb.Car.X = sth else