跳至主要内容

[Golang] Design Pattern

golang

Functional Options

資料來源:GO 程式設計模式:FUNCTIONAL OPTIONS @ 陳皓

在 Go 中需要為某些 struct (通常是一些設定),可以同時有預設值的,但有希望可以客製化設定時,可以使用這個方式:

  • 定義需要可以被 config 的 struct,例如 Server
  • 定義一個能夠接收 *Server 為參數的型別,例如 Option
  • 定義許多能夠修改 Server 欄位值的函式,例如 Protocol, Timeout, 等等
  • 定義 NewServer 函式,在這個函式中會有 Server 的預設值,並且可以透過呼叫函式修改設定
// 程式碼來源:https://coolshell.cn/articles/21146.html
// @ 陳皓

// Server 定義可以接收的參數欄位
type Server struct {
Addr string
Port int
Protocol string
Timeout time.Duration
Maxconns int
TLS *tls.Config
}

// Option 的型別是可以接受 *Server 為參數的函式
type Option func(*Server)

// Protocol 用來為 Server 添加 Protocol 欄位
func Protocol(p string) Option {
return func(s *Server) {
s.Protocol = p
}
}

// Timeout 用來為 Server 添加 Timeout 欄位
func Timeout(timeout time.Duration) Option {
return func(s *Server) {
s.Timeout = timeout
}
}

// MaxConns 用來為 Server 添加 MaxConns 欄位
func MaxConns(maxconns int) Option {
return func(s *Server) {
s.Maxconns = maxconns
}
}

// TLS 用來為 Server 添加 TLS 欄位
func TLS(tls *tls.Config) Option {
return func(s *Server) {
s.TLS = tls
}
}

// NewServer 用來建立 Server 物件,並可以根據 options 回傳
func NewServer(addr string, port int, options ...func(*Server)) (*Server, error) {
// server 的預設值定在這
server := Server{
Addr: addr,
Port: port,
Protocol: "tcp",
Timeout: 30 * time.Second,
Maxconns: 1000,
TLS: nil,
}

for _, option := range options {
option(&server)
}

return &server, nil
}

func main() {
s1, _ := NewServer("localhost", 1024)
fmt.Printf("server 1: %+v \n", s1)

s2, _ := NewServer("localhost", 2048, Protocol("udp"))
fmt.Printf("server 1: %+v \n", s2)

s3, _ := NewServer("localhost", 8080, Timeout(300*time.Second), MaxConns(1000))
fmt.Printf("server 1: %+v \n", s3)
}