Ce este
Modelul Builder construiește un obiect complex pas cu pas. În loc de un singur constructor cu o listă lungă și confuză de argumente, builder-ul oferă pași mici, cu nume — și un Build() final care returnează obiectul terminat.
În Go, pașii returnează de obicei chiar builder-ul, așa că apelurile se înlănțuie într-o frază ușor de citit.
Exemplu: construirea unei pizza
Compară NewPizzaBuilder("large").Cheese().Topping("mushrooms") cu un constructor de forma NewPizza("large", true, []string{...}) — builder-ul spune ce înseamnă fiecare valoare, iar părțile opționale sunt pur și simplu omise.
Pași care se înlănțuie
Fiecare pas are un nume și este opțional: pizza mică îi sare pe toți. Fără supa de argumente true, nil, false.
Ieșire: program Go și rezultatul capturat
package main
import "fmt"
type Pizza struct {
size string
cheese bool
toppings []string
}
type PizzaBuilder struct {
pizza Pizza
}
func NewPizzaBuilder(size string) *PizzaBuilder {
return &PizzaBuilder{pizza: Pizza{size: size}}
}
func (b *PizzaBuilder) Cheese() *PizzaBuilder {
b.pizza.cheese = true
return b
}
func (b *PizzaBuilder) Topping(t string) *PizzaBuilder {
b.pizza.toppings = append(b.pizza.toppings, t)
return b
}
func (b *PizzaBuilder) Build() Pizza {
return b.pizza
}
func main() {
// Fiecare pas este opțional și se leagă de următorul.
big := NewPizzaBuilder("mare").
Cheese().
Topping("ciuperci").
Topping("măsline").
Build()
// Pizza simplă: sare peste toți pașii opționali.
small := NewPizzaBuilder("mică").Build()
fmt.Printf("pizza %s, brânză: %v, ingrediente: %v\n", big.size, big.cheese, big.toppings)
fmt.Printf("pizza %s, brânză: %v, ingrediente: %v\n", small.size, small.cheese, small.toppings)
}
Când să îl folosești
Folosește-l când un obiect are multe părți opționale sau când construcția are pași reali care merită nume. Cererile, interogările și configurările sunt teritoriul clasic al builder-ului.
Renunță la el pentru structuri simple — literalul de structură din Go Pizza{size: "large"}, cu câmpuri denumite, este deja un mic builder foarte bun pentru cazurile ușoare.
Avantaje și dezavantaje
Avantaje: construcție ușor de citit; părți opționale fără liste uriașe de argumente; obiectul poate fi validat o singură dată, în Build().
Dezavantaje: încă un tip de scris și de întreținut; este exagerat acolo unde un literal de structură se citește deja bine.