안녕하세요.
이번 포스팅에서는 Go를 활용해 Builder Pattern을 구현해보도록 하겠습니다.
Builder Pattern은 복잡한 객체를 생성하는 부분과 표현하는 부분을 분리하여, 동일한 절차에서도 서로 다른 표현을 생성하는 방법을 제공해줍니다.
package main
import (
"fmt"
"strconv"
)
type Color string
type Make string
type Model string
const (
BLUE Color = "blue"
RED = "red"
)
type car struct {
topSpeed int
color Color
}
type Car interface {
Drive() string
Stop() string
}
type CarBuilder interface {
TopSpeed(int) CarBuilder
Paint(Color) CarBuilder
Build() Car
}
type carBuilder struct {
speedOption int
color Color
}
func (cb *carBuilder) TopSpeed(speed int) CarBuilder {
cb.speedOption = speed
return cb
}
func (cb *carBuilder) Paint(color Color) CarBuilder {
cb.color = color
return cb
}
func (cb *carBuilder) Build() Car {
return &car{
topSpeed: cb.speedOption,
color: cb.color,
}
}
func New() CarBuilder {
return &carBuilder{}
}
func (c *car) Drive() string {
return "Driving at speed: " + strconv.Itoa(c.topSpeed)
}
func (c *car) Stop() string {
return "Stopping a " + string(c.color) + " car"
}
func main() {
assembly := builder.New()
car := assembly.TopSpeed(1).Build()
fmt.Println(car.Drive())
}
이 코드에서의 핵심은 interface에서의 duck typing입니다. struct들에 interface코드들을 구현해줌으로써 사용해주기만 하면 됩니다. 위 코드에서도 보시면 CarBuilder를 사용할때 보시면 carbuilder를 통해 코드를 구현하고 값을 리턴할 때 carbuilder를 활용해 duck typeing하는 것을 보실 수 있습니다. 이런 방법으로 코드를 구현하시면 됩니다.
코드의 결과로는 다음과 같이 나오는 걸 보실 수 있습니다.
main 메소드에서 "assembly := New()" 이렇게 한게 아니라 "assembly := builder.New()" 이렇게 하신 이유가 있나요?