Builder Design Pattern

rflpazini

Rafael Pazini

Posted on July 4, 2024

Builder Design Pattern

O padrão de design Builder é utilizado para construir objetos complexos de forma incremental, permitindo a criação de diferentes representações de um objeto utilizando o mesmo processo de construção. Neste artigo, vamos explorar como implementar o padrão Builder em Golang, entender seus benefícios e analisar um exemplo prático de uso.

O que é o Builder?

O padrão Builder separa a construção de um objeto complexo da sua representação, permitindo que o mesmo processo de construção possa criar diferentes representações. Isso é especialmente útil quando um objeto precisa ser criado em várias etapas ou com várias configurações possíveis.

Benefícios do Builder

  • Separação de Construção e Representação: Permite que a construção de um objeto seja separada da sua representação final.
  • Construção Incremental: Permite a construção de objetos complexos de maneira incremental e passo a passo.
  • Reutilização de Código: Facilita a reutilização de código ao definir passos de construção comuns que podem ser combinados de várias maneiras.

Implementando um Builder

Para implementar nosso Builder, vamos imaginar um objeto complexo onde será necessário inicializar vários campos e até outros objetos agrupados. Que tal uma Casa? Onde teremos dois tipos de construção, uma convencional onde será usado concreto e tijolos, e uma segunda de madeira.

1 - Definindo a Estrutura

Primeiro, precisamos definir a estrutura do objeto que queremos construir. Como dito antes, vamos construir uma casa. Dentro dessa Struct colocaremos o que é necessário para criar uma.

// house.go

package main

type House struct {
    Foundation string
    Structure  string
    Roof       string
    Interior   string
}
Enter fullscreen mode Exit fullscreen mode

2 - Definindo a Interface do Builder

Ainda no mesmo arquivo, vamos definir a interface do nosso Builder que especifica os métodos necessários para construir as diferentes partes da House.

//house.go

package main

type House struct {
    Foundation string
    Structure  string
    Roof       string
    Interior   string
}

type HouseBuilder interface {
    SetFoundation()
    SetStructure()
    SetRoof()
    SetInterior()
    GetHouse() House
}
Enter fullscreen mode Exit fullscreen mode

3 - Implementando concretamente o Builder

Vamos criar dois arquivos novos, concreteHouse e woodHouse. Eles serão a implementação de uma classe concreta que siga a interface HouseBuilder.

//concreteHouse.go

package main

type ConcreteHouseBuilder struct {
    house House
}

func (b *ConcreteHouseBuilder) SetFoundation() {
    b.house.Foundation = "Concrete, brick, and stone"
}

func (b *ConcreteHouseBuilder) SetStructure() {
    b.house.Structure = "Wood and brick"
}

func (b *ConcreteHouseBuilder) SetRoof() {
    b.house.Roof = "Concrete and reinforced steel"
}

func (b *ConcreteHouseBuilder) SetInterior() {
    b.house.Interior = "Gypsum board, plywood, and paint"
}

func (b *ConcreteHouseBuilder) GetHouse() House {
    return b.house
}
Enter fullscreen mode Exit fullscreen mode
//woodHouse.go

package main

type WoodHouseBuilder struct {
    house House
}

func (b *WoodHouseBuilder) SetFoundation() {
    b.house.Foundation = "Wooden piles"
}

func (b *WoodHouseBuilder) SetStructure() {
    b.house.Structure = "Wooden frame"
}

func (b *WoodHouseBuilder) SetRoof() {
    b.house.Roof = "Wooden shingles"
}

func (b *WoodHouseBuilder) SetInterior() {
    b.house.Interior = "Wooden panels and paint"
}

func (b *WoodHouseBuilder) GetHouse() House {
    return b.house
}
Enter fullscreen mode Exit fullscreen mode

4 - Definindo o Director

O Director é uma classe que gerencia a construção de um objeto, garantindo que as etapas de construção sejam chamadas na ordem correta. Ele não sabe nada sobre os detalhes das implementações específicas do Builder, apenas chama os métodos do Builder em uma sequência lógica para criar o produto final.

//director.go

package main

type Director struct {
    builder HouseBuilder
}

func (d *Director) Build() {
    d.builder.SetFoundation()
    d.builder.SetStructure()
    d.builder.SetRoof()
    d.builder.SetInterior()
}

func (d *Director) SetBuilder(b HouseBuilder) {
    d.builder = b
}
Enter fullscreen mode Exit fullscreen mode

5 - Utilizando o Builder

Finalmente, vamos utilizar o Director e os Builders concretos para construir diferentes tipos de casas.

//main.go

package main

import (
    "fmt"
)

func main() {
    cb := &builder.ConcreteHouseBuilder{}
    director := builder.Director{Builder: cb}

    director.Build()
    concreteHouse := cb.GetHouse()

    fmt.Println("Concrete House")
    fmt.Println("Foundation:", concreteHouse.Foundation)
    fmt.Println("Structure:", concreteHouse.Structure)
    fmt.Println("Roof:", concreteHouse.Roof)
    fmt.Println("Interior:", concreteHouse.Interior)
    fmt.Println("-------------------------------------------")

    wb := &builder.WoodHouseBuilder{}
    director.SetBuilder(wb)

    director.Build()
    woodHouse := wb.GetHouse()

    fmt.Println("Wood House")
    fmt.Println("Foundation:", woodHouse.Foundation)
    fmt.Println("Structure:", woodHouse.Structure)
    fmt.Println("Roof:", woodHouse.Roof)
    fmt.Println("Interior:", woodHouse.Interior)
}
Enter fullscreen mode Exit fullscreen mode

Resumindo

  1. Struct House: Representa o produto final que estamos construindo.
  2. Interface HouseBuilder: Define os métodos para construir as diferentes partes da casa.
  3. Implementações Concretas (ConcreteHouseBuilder e WoodHouseBuilder): Implementam a interface HouseBuilder e definem as etapas de construção específicas.
  4. Director: Gerencia o processo de construção, garantindo que as etapas sejam chamadas na ordem correta.
  5. Função main: Demonstra o uso do padrão Builder para construir diferentes tipos de casas, chamando o Director para gerenciar o processo e obtendo o produto final.

Conclusão

O padrão Builder é uma ferramenta para construir objetos complexos de maneira incremental e flexível. Em Golang, a implementação deste padrão é direta e eficaz, permitindo a criação de sistemas modulares e fáceis de manter. Com o uso de interfaces e classes concretas, podemos centralizar a lógica de construção e simplificar a evolução do código à medida que novos requisitos surgem.

💖 💪 🙅 🚩
rflpazini
Rafael Pazini

Posted on July 4, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Builder Design Pattern
go Builder Design Pattern

July 4, 2024