Builder Design Pattern
Rafael Pazini
Posted on July 4, 2024
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
}
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
}
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
}
//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
}
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
}
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)
}
Resumindo
- Struct
House
: Representa o produto final que estamos construindo. - Interface
HouseBuilder
: Define os métodos para construir as diferentes partes da casa. - Implementações Concretas (
ConcreteHouseBuilder
eWoodHouseBuilder
): Implementam a interfaceHouseBuilder
e definem as etapas de construção específicas. -
Director
: Gerencia o processo de construção, garantindo que as etapas sejam chamadas na ordem correta. - 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.
Posted on July 4, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.