Go 언어로 서버 프레임워크를 개발한다고 가정해봅시다. 서버는 다양한 옵션을 가질 수 있으며, 생성자를 통해 이를 설정할 수 있어야 합니다. 예를 들어 서버의 주소, 읽기 타임아웃, 로깅 등의 옵션을 설정할 수 있어야 하는데요. 예시를 들어보겠습니다.
// 예시
위와 같이 이러한 옵션은 필수적이거나 선택적일 수 있습니다. 그렇다면 저 상황에서 다른 옵션이 추가된다면 어떨까요? 그에 맞게 생성자를 추가해야하고, 각 옵션이 optional하다면 추가해야하는 생성자가 기하급수적으로 늘어납니다. 물론 메서드 오버로딩을 지원하지 않는 특성 상, 네이밍도 상당히 어렵습니다. 오늘 이야기 해보려 하는 Functional Option Pattern은 이러한 문제를 해결하고자 등장한 패턴입니다.
Functional Option Pattern
Functional Option Pattern은 생성자에 파라미터로 함수를 받아 필요한 옵션을 설정하는 방식입니다. 함수를 사용함으로써 유연성을 가지며, 필드의 기본값과 zero value를 구분할 수 있습니다. 또한 필드의 추가나 변경에도 자유롭게 대응할 수 있는데요.
위와 유사한 예시의 Server를 기반으로 Functional Option Pattern을 적용해보겠습니다.
type Server struct {
Address string
ReadTimeout time.Duration
Logger *log.Logger
}
func NewServer(options ...func(*Server)) *Server {
s := &Server{
Address: ":8080",
ReadTimeout: time.Second * 10,
Logger: log.Default(),
}
for _, option := range options {
option(s)
}
return s
}
위 코드에서는 `Server` 구조체와 `NewServer` 생성자 함수를 정의하였습니다. `Server` 구조체는 서버의 주소(`Address`), 읽기 타임아웃(`ReadTimeout`), 로거(`Logger`) 등을 포함하고 있습니다. `NewServer` 함수는 `Server` 구조체를 생성하는 생성자 함수로, 가변인자를 받아 옵션을 설정합니다.
option 함수는 아래와 같이 짜서 사용할 수 있습니다.
func WithAddress(address string) func(*Server) {
return func(s *Server) {
s.Address = address
}
}
func WithReadTimeout(timeout time.Duration) func(*Server) {
return func(s *Server) {
s.ReadTimeout = timeout
}
}
func WithLogger(logger *log.Logger) func(*Server) {
return func(s *Server) {
s.Logger = logger
}
}
위의 예제에서는 `WithAddress`, `WithReadTimeout`, `WithLogger` 함수를 정의하여 각각의 옵션을 설정합니다. 각 함수는 `Server` 구조체에 대한 함수를 반환합니다. 반환된 함수는 생성자 함수에서 호출되어 해당 옵션을 설정하게 됩니다.
이제 위에서 만든 생성자 함수를 호출하여 구조체를 생성해보겠습니다.
func main() {
server := NewServer(
WithAddress(":8000"),
WithReadTimeout(time.Minute),
WithLogger(log.New(os.Stdout, "", log.LstdFlags)),
)
server.Start()
}
위의 코드에서는 `NewServer` 생성자 함수를 호출하여 서버를 생성합니다. `WithAddress`, `WithReadTimeout`, `WithLogger` 함수를 사용하여 주소, 읽기 타임아웃, 로거 등을 설정합니다. 생성된 서버 구조체를 사용하여 서버를 시작하거나 필요한 작업을 수행할 수 있습니다.
'Golang' 카테고리의 다른 글
Golang과 함께하는 테스트 여정 - 통합 테스트 (0) | 2023.05.21 |
---|---|
Golang과 함께하는 테스트 여정 - 단위 테스트 (0) | 2023.05.05 |
gin은 어떻게 요청을 받는가 (2) | 2023.04.23 |
속성 기반 테스트 in Golang (Property Based Testing) (0) | 2023.03.26 |
Datadog APM with Golang 1 - 배경 이야기 (1) | 2023.02.25 |
댓글