Builder - is a creational design pattern that separates the construction of a complex object from its representation, so that the same construction process can result in different representations. This is typically implemented using a method chaining where each method returns the builder instance.
This pattern is used when:
The pattern operates with four entities:
package main
import (
"encoding/json"
"errors"
"fmt"
)
type AbstractPCBuilder interface {
SetupMotherboard(mb Motherboard) error
SetupCPU(cpu CPU) error
SetupRAM(ram RAM) error
SetupGPU(gpu GPU) error
SetupPSU(psu PSU) error
FinalizePC() (*PC, error)
}
type Motherboard struct {
RAMSlots int
Socket string
}
type CPU struct {
CoreCount uint8
PowerConsumption int
Socket string
}
type RAM struct {
Capacity int
}
type GPU struct {
PowerConsumption int
}
type PSU struct {
Power int
}
type PC struct {
Motherboard *Motherboard
CPU *CPU
RAM []RAM
GPU *GPU
PSU *PSU
}
func (c PC) PowerON() {
fmt.Println("Successfully powered on")
}
type WorkStationBuilder struct {
pc *PC
}
func NewWorkStationBuilder() AbstractPCBuilder {
return &WorkStationBuilder{
pc: &PC{},
}
}
func (b *WorkStationBuilder) SetupMotherboard(mb Motherboard) error {
if b.pc.Motherboard != nil {
return errors.New("Motherboard already installed")
}
if len(b.pc.RAM) > mb.RAMSlots {
return errors.New("inappropriate number of RAM slots")
}
if b.pc.CPU != nil && b.pc.CPU.Socket != mb.Socket {
return errors.New("CPU and motherboard socket mismatch")
}
b.pc.Motherboard = &mb
return nil
}
func (b *WorkStationBuilder) SetupCPU(cpu CPU) error {
if b.pc.CPU != nil {
return errors.New("CPU already installed")
}
if cpu.CoreCount > 4 || cpu.PowerConsumption > 80 {
return errors.New("too powerfull cpu")
}
if b.pc.PSU != nil && (cpu.PowerConsumption/b.pc.PSU.Power*100) > 60 {
return errors.New("PSU too weak for these CPU")
}
if b.pc.Motherboard != nil && b.pc.Motherboard.Socket != cpu.Socket {
return errors.New("CPU and motherboard socket mismatch")
}
b.pc.CPU = &cpu
return nil
}
func (b *WorkStationBuilder) SetupRAM(ram RAM) error {
if b.pc.Motherboard != nil && b.pc.Motherboard.RAMSlots <= len(b.pc.RAM) {
return errors.New("motherboard RAM slots are full")
}
if ram.Capacity < 1 || ram.Capacity > 4 {
return errors.New("bad RAM capacity")
}
b.pc.RAM = append(b.pc.RAM, ram)
return nil
}
func (b *WorkStationBuilder) SetupGPU(gpu GPU) error {
return errors.New("workstation doesn't need discrete GPU")
}
func (b *WorkStationBuilder) SetupPSU(psu PSU) error {
if b.pc.PSU != nil {
return errors.New("PSU already installed")
}
consumption := 0
if b.pc.CPU != nil {
consumption += b.pc.CPU.PowerConsumption
}
b.pc.PSU = &psu
return nil
}
func (b *WorkStationBuilder) FinalizePC() (*PC, error) {
if b.pc.CPU == nil ||
b.pc.Motherboard == nil ||
len(b.pc.RAM) == 0 ||
b.pc.PSU == nil {
return nil, errors.New("workstation built can't be finalized")
}
return b.pc, nil
}
func main() {
pcBuilder := NewWorkStationBuilder()
err := pcBuilder.SetupCPU(CPU{
CoreCount: 4,
PowerConsumption: 60,
Socket: "AM5",
})
if err != nil {
panic(err)
}
err = pcBuilder.SetupPSU(PSU{
Power: 200,
})
if err != nil {
panic(err)
}
for range 4 {
err = pcBuilder.SetupRAM(RAM{
Capacity: 1,
})
if err != nil {
panic(err)
}
}
err = pcBuilder.SetupMotherboard(Motherboard{
RAMSlots: 4,
Socket: "AM5",
})
if err != nil {
panic(err)
}
pc, err := pcBuilder.FinalizePC()
if err != nil {
panic(err)
}
d, _ := json.MarshalIndent(pc, "", " ")
fmt.Printf("%s\n", d)
pc.PowerON()
}