Analysis
The Builder pattern is used when the desired product is complex and requires multiple steps to complete. In this case, several construction methods would be simpler than a single monstrous constructor. The potential problem with the multistage building process is that a partially built and unstable product may be exposed to the client. The Builder pattern keeps the product private until it’s fully built.
In the below code, we see different types of houses (igloo
and normalHouse
) being constructed by iglooBuilder
and normalBuilder
. Each house type has the same construction steps. The optional director struct helps to organize the building process.
Refer to https://swsmile.info/post/design-pattern-builder-pattern/ for Builder pattern.
Demo
iBuilder.go: Builder interface
package main
type iBuilder interface {
setWindowType()
setDoorType()
setNumFloor()
getHouse() house
}
func getBuilder(builderType string) iBuilder {
if builderType == "normal" {
return &normalBuilder{}
}
if builderType == "igloo" {
return &iglooBuilder{}
}
return nil
}
normalBuilder.go: Concrete builder
package main
type normalBuilder struct {
windowType string
doorType string
floor int
}
func newNormalBuilder() *normalBuilder {
return &normalBuilder{}
}
func (b *normalBuilder) setWindowType() {
b.windowType = "Wooden Window"
}
func (b *normalBuilder) setDoorType() {
b.doorType = "Wooden Door"
}
func (b *normalBuilder) setNumFloor() {
b.floor = 2
}
func (b *normalBuilder) getHouse() house {
return house{
doorType: b.doorType,
windowType: b.windowType,
floor: b.floor,
}
}
iglooBuilder.go: Concrete builder
package main
type iglooBuilder struct {
windowType string
doorType string
floor int
}
func newIglooBuilder() *iglooBuilder {
return &iglooBuilder{}
}
func (b *iglooBuilder) setWindowType() {
b.windowType = "Snow Window"
}
func (b *iglooBuilder) setDoorType() {
b.doorType = "Snow Door"
}
func (b *iglooBuilder) setNumFloor() {
b.floor = 1
}
func (b *iglooBuilder) getHouse() house {
return house{
doorType: b.doorType,
windowType: b.windowType,
floor: b.floor,
}
}
house.go: Product
package main
type house struct {
windowType string
doorType string
floor int
}
director.go: Director
package main
type director struct {
builder iBuilder
}
func newDirector(b iBuilder) *director {
return &director{
builder: b,
}
}
func (d *director) setBuilder(b iBuilder) {
d.builder = b
}
func (d *director) buildHouse() house {
d.builder.setDoorType()
d.builder.setWindowType()
d.builder.setNumFloor()
return d.builder.getHouse()
}
main.go: Client code
package main
import "fmt"
func main() {
normalBuilder := getBuilder("normal")
iglooBuilder := getBuilder("igloo")
director := newDirector(normalBuilder)
normalHouse := director.buildHouse()
fmt.Printf("Normal House Door Type: %s\n", normalHouse.doorType)
fmt.Printf("Normal House Window Type: %s\n", normalHouse.windowType)
fmt.Printf("Normal House Num Floor: %d\n", normalHouse.floor)
director.setBuilder(iglooBuilder)
iglooHouse := director.buildHouse()
fmt.Printf("\nIgloo House Door Type: %s\n", iglooHouse.doorType)
fmt.Printf("Igloo House Window Type: %s\n", iglooHouse.windowType)
fmt.Printf("Igloo House Num Floor: %d\n", iglooHouse.floor)
}
// output
Normal House Door Type: Wooden Door
Normal House Window Type: Wooden Window
Normal House Num Floor: 2
Igloo House Door Type: Snow Door
Igloo House Window Type: Snow Window
Igloo House Num Floor: 1