选项模式
2023/8/6大约 2 分钟
提示
由于Go语言不支持重载函数,当我们需要使用不同的方式构建对象时,不得不使用多个构造函数进行初始化。
对于多参数的类的初始化遇到哪些困境?
例如:HTTP Server的初始化
type Server struct {
	Addr     string
	Port     int
	Protocol string
	Timeout  time.Duration
	MaxConns int
	TLS      *tls.Config
}为了支持不同功能的Server,我们不得不通过不同的函数命名和参数,构造初始化函数。
// NewTLSServer 带TLS的初始化函数
func NewTLSServer(addr string, port int, tls *tls.Config) (*Server, error) {
	return &Server{
		Addr:     addr,
		Port:     port,
		Protocol: "tcp",
		Timeout:  time.Second * 30,
		MaxConns: 100,
		TLS:      tls,
	}, nil
}
// NewServerWithTimeout 带超时时间的初始化函数
func NewServerWithTimeout(addr string, port int, timeout time.Duration) (*Server, error) {
	return &Server{
		Addr:     addr,
		Port:     port,
		Protocol: "tcp",
		Timeout:  timeout,
		MaxConns: 100,
		TLS:      nil,
	}, nil
}
// NewTLSServerWithMaxConnAndTimeout 支持TLS和最大连接数和超时时间的初始化函数
func NewTLSServerWithMaxConnAndTimeout(addr string, port int, maxconns int, timeout time.Duration, tls *tls.Config) (*Server, error) {
	return &Server{
		Addr:     addr,
		Port:     port,
		Protocol: "tcp",
		Timeout:  timeout,
		MaxConns: maxconns,
		TLS:      tls,
	}, nil
}一圈写下来,发现这仅不禁无法列举所有的功能场景,而且代码冗余非常多。
那么Option(选项模式)是如何解决这个问题的呢?
首先:定义一个Option函数,参数为Server指针
type Option func(*Server)如果关注错误的话,可以定义如下
type Option func(*Server) error其次:定义各种初始化选项函数,通常返回上文定义的Option
func WithProtocol(protocol string) Option {
	return func(s *Server) {
		s.Protocol = protocol
	}
}
func WithTimeout(timeout time.Duration) Option {
	return func(s *Server) {
		s.Timeout = timeout
	}
}
func WithMaxConns(maxconns int) Option {
	return func(s *Server) {
		s.MaxConns = maxconns
	}
}
func WihtTLS(tls *tls.Config) Option {
	return func(s *Server) {
		s.TLS = tls
	}
}通常:我们定义一个全局的初始化函数,使用Go语言可变参数Option
func NewServer(addr string, port int, options ...Option) (*Server, error) {
	srv := Server{
		Addr:     addr,
		Port:     port,
		Protocol: "tcp",
		Timeout:  time.Second * 30,
		MaxConns: 100,
		TLS:      nil,
	}
	for _, option := range options {
		option(&srv)
	}
	//...
	return &srv, nil
}最后,我们看看最终效果
s1, _ := NewServer("localhost", 1024) //默认的Server
s2, _ := NewServer("localhost", 2048, WithProtocol("udp")) //协议为udp的Server
s3, _ := NewServer("0.0.0.0", 8080, WithTimeout(300*time.Second), WithMaxConns(1000)) //支持超时时间和最大连接的Server总结
由于Go语言函数不支持重载,因此在多参数的类的初始化中,我们遇到初始化函数冗余问题, 我们可以通过Option(选项模式),可以很自由的定义类的初始化,解决前面遇到的问题。
这里本质上使用了Go语言以下特点:
- 闭包,With...等Option的定义,通过闭包的方式,扩展了Option的场景;
- 可变参数,(options ...option),通过可变参数,我们可以自由选择Option;
