1. Builder Pattern

Person 객체를 예로 들어보자

type Person struct {
    name   string
    age    int
    job    string
    height float32
    weight float32
}

func NewPerson(name string, age int, job string, height float32, weight float32) *Person {
    return &Person{
        name,
        age,
        job,
        height,
        weight,
    }
}

func main() {
    p := NewPerson("홍길동", 22, "developer", 177.2, 72.9)
}

위처럼 모든 정보를 입력하지 않아도 될때도 있고, 가독성도 좋지않으며 parameter의 순서도 맞춰주어야한다.

또 객체에 새로운 정보가 추가된다면 NewPerson()을 계속 수정해주어야 한다.

이를 해결하기 위해 Builder를 이용해보자.

type Person struct {
    name   string
    age    int
    job    string
    height float32
    weight float32
}

type PersonBuilder struct {
    person *Person
}

func NewPersonBuilder() *PersonBuilder {
    return &PersonBuilder{&Person{}}
}

func (b *PersonBuilder) Name(name string) *PersonBuilder {
    b.name = name
    return b
}

func (b *PersonBuilder) Age(age int) *PersonBuilder {
    b.age = age
    return b
}

func (b *PersonBuilder) Job(job string) *PersonBuilder {
    b.job = job
    return b
}

func (b *PersonBuilder) Height(height float32) *PersonBuilder {
    b.height = height
    return b
}

func (b *PersonBuilder) Weight(weight float32) *PersonBuilder {
    b.weight = weight
    return b
}

func (b *PersonBuilder) Build() *Person {
    return b.person
}

func main() {
    pb := NewPersonBuilder().
        Age(22).
        Height(177.2).
        Weight(72.9).
        Name("홍길동").
        Job("developer")
    
    p := pb.Build()
}

순서를 맞추지 않아도 되고 가독성도 좋아졌다.

2. 함수형으로 Builder Pattern 사용

type Person struct {
    name   string
    age    int
    job    string
    height float32
    weight float32
}

type modPerson func(*Person)

type PersonBuilder struct {
    actions []modPerson
}

func (b *PersonBuilder) Name(name string) *PersonBuilder {
    b.actions = append(b.actions, func(p *Person) {
        p.name = name
    })
    return b
}

func (b *PersonBuilder) Age(age int) *PersonBuilder {
    b.actions = append(b.actions, func(p *Person) {
        p.age = age
    })
    return b
}

func (b *PersonBuilder) Job(job string) *PersonBuilder {
    b.actions = append(b.actions, func(p *Person) {
        p.job = job
    })
    return b
}

func (b *PersonBuilder) Height(height float32) *PersonBuilder {
    b.actions = append(b.actions, func(p *Person) {
        p.height = height
    })
    return b
}

func (b *PersonBuilder) Weight(weight float32) *PersonBuilder {
    b.actions = append(b.actions, func(p *Person) {
        p.weight = weight
    })
    return b
}

func (b *PersonBuilder) Build() *Person {
    p := &Person{}
    for _, action := range b.actions {
        action(p)
    }
    return p
}

func NewPersonBuilder() *PersonBuilder {
    return &PersonBuilder{}
}

func main() {
    pb := NewPersonBuilder().
        Age(22).
        Height(177.2).
        Weight(72.9).
        Name("홍길동").
        Job("developer")
    
    p := pb.Build()
}