强烈推荐使用Functional Options这种方式,这种方式至少带来了如下的好处:
- 直觉式的编程
- 高度的可配置化
- 很容易维护和扩展
- 自文档
- 对于新来的人很容易上手
- 没有什么令人困惑的事(是nil 还是空)
type Server struct {
Addr string
Port int
Protocol string
Timeout time.Duration
MaxConns int
TLS *tls.Config
}
type Option func(*Server)
func Protocol(p string) Option {
return func(s *Server) {
s.Protocol = p
}
}
func Timeout(timeout time.Duration) Option {
return func(s *Server) {
s.Timeout = timeout
}
}
func MaxConns(maxconns int) Option {
return func(s *Server) {
s.MaxConns = maxconns
}
}
func TLS(tls *tls.Config) Option {
return func(s *Server) {
s.TLS = tls
}
}
/*
上面这组代码传入一个参数,然后返回一个函数,返回的这个函数会设置自己的 Server 参数。例如:
当我们调用其中的一个函数用 MaxConns(30) 时
其返回值是一个 func(s* Server) { s.MaxConns = 30 } 的函数。
这个叫高阶函数。在数学上,就好像这样的数学定义,计算长方形面积的公式为: rect(width, height) = width * height; 这个函数需要两个参数,我们包装一下,就可以变成计算正方形面积的公式:square(width) = rect(width, width) 也就是说,squre(width)返回了另外一个函数,这个函数就是rect(w,h) 只不过他的两个参数是一样的。即:f(x) = g(x, x)
*/
//有一个可变参数 options 其可以传出多个上面上的函数,然后使用一个for-loop来设置我们的 Server 对象
func NewServer(addr string, port int, options ...func(*Server)) (*Server, error) {
srv := Server{
Addr: addr,
Port: port,
Protocol: "tcp",
Timeout: 30 * time.Second,
MaxConns: 1000,
TLS: nil,
}
for _, option := range options {
option(&srv)
}
//...
return &srv, nil
}
//创建server对象
s1, _ := NewServer("localhost", 1024)
s2, _ := NewServer("localhost", 2048, Protocol("udp"))
s3, _ := NewServer("0.0.0.0", 8080, Timeout(300*time.Second), MaxConns(1000))