Sobes.tech
Middle

Tell me about the Builder design pattern.

sobes.tech AI

Answer from AI

Builder is a creational pattern that allows constructing complex objects step by step.

It is used when:

  • The process of creating an object is complex and involves many steps.
  • There is a need to create different representations of the same object.
  • The constructor of the object has many optional parameters.

The pattern consists of the following roles:

  • Builder: An interface defining the steps to build an object.
  • ConcreteBuilder: A specific implementation of Builder that performs the building steps and provides a method to get the finished object.
  • Product: The complex object that is being built.
  • Director (Optional): Defines the order of calling the building steps.

Example implementation in Golang without Director:

// Product - the object we are building
type Pizza struct {
	Dough   string
	Sauce   string
	Toppings []string
}

// Builder - the builder interface
type PizzaBuilder interface {
	SetDough(dough string) PizzaBuilder
	SetSauce(sauce string) PizzaBuilder
	AddTopping(topping string) PizzaBuilder
	Build() Pizza // Method to get the finished object
}

// ConcreteBuilder - the specific implementation of the builder
type HawaiianPizzaBuilder struct {
	pizza Pizza
}

func NewHawaiianPizzaBuilder() *HawaiianPizzaBuilder {
	return &HawaiianPizzaBuilder{}
}

func (b *HawaiianPizzaBuilder) SetDough(dough string) PizzaBuilder {
	b.pizza.Dough = dough
	return b
}

func (b *HawaiianPizzaBuilder) SetSauce(sauce string) PizzaBuilder {
	b.pizza.Sauce = sauce
	return b
}

func (b *HawaiianPizzaBuilder) AddTopping(topping string) PizzaBuilder {
	b.pizza.Toppings = append(b.pizza.Toppings, topping)
	return b
}

func (b *HawaiianPizzaBuilder) Build() Pizza {
	return b.pizza
}

// Usage example
func main() {
	// Create a builder for Hawaiian pizza
	builder := NewHawaiianPizzaBuilder()

	// Build the pizza step by step
	pizza := builder.
		SetDough("thin").
		SetSauce("tomato").
		AddTopping("pineapple").
		AddTopping("ham").
		Build() // Get the finished pizza

	fmt.Printf("Created pizza: %+v\n", pizza)
}

Advantages of the pattern:

  • Allows isolating the process of building a complex object from its representation.
  • Ensures step-by-step creation of the object.
  • Simplifies creating different representations of the same object.
  • Makes the code for creating an object more readable and maintainable when there are many parameters.

Disadvantages of the pattern:

  • Increases the number of classes in the project.
  • Can be redundant for simple objects.