GO编程模式学习笔记系列为学习陈皓的GO编程模式系列文章记录与心得。
原文链接:GO 编程模式:FUNCTIONAL OPTIONS
首先FUNCTIONAL OPTIONS只是一种模式,并不是必须的,个人感觉和替代者比,也未见得优势多明显,了解这种模式可以在读代码或者用第三方库的时候更轻松。主要是使用这种模式会让你的代码更具有Go语言风格,让你散发着gopher的独特气质。
如果一个对象的初始化配置项众多,且有很多可以使用默认值,也可以自定义,那么就可以使用以下三种方式解决:
1.必填项和选填项分离
func NewServer(addr string, port int, conf *Config) (*Server, error) {
//...
}
//Using the default configuratrion
srv1, _ := NewServer("localhost", 9000, nil)
conf := ServerConfig{Protocol:"tcp", Timeout: 60*time.Duration}
srv2, _ := NewServer("locahost", 9000, &conf)
其中addr和port是必填项,conf是选填,需要注意的是,如果conf只填充了一部分配置,在NewServer 中要给其他配置默认值。可以设置一个全是默认值的对象, 替换用户传入的部分。可能会有很多nil或者默认值的判断,所以还是有点烦的。
2.builder模式
//使用一个builder类来做包装
type ServerBuilder struct {
Server
}
func (sb *ServerBuilder) Create(addr string, port int) *ServerBuilder {
sb.Server.Addr = addr
sb.Server.Port = port
//其它代码设置其它成员的默认值
return sb
}
func (sb *ServerBuilder) WithProtocol(protocol string) *ServerBuilder {
sb.Server.Protocol = protocol
return sb
}
func (sb *ServerBuilder) WithMaxConn( maxconn int) *ServerBuilder {
sb.Server.MaxConns = maxconn
return sb
}
func (sb *ServerBuilder) WithTimeOut( timeout time.Duration) *ServerBuilder {
sb.Server.Timeout = timeout
return sb
}
func (sb *ServerBuilder) WithTLS( tls *tls.Config) *ServerBuilder {
sb.Server.TLS = tls
return sb
}
func (sb *ServerBuilder) Build() (Server) {
return sb.Server
}
使用
sb := ServerBuilder{}
server, err := sb.Create("127.0.0.1", 8080).
WithProtocol("udp").
WithMaxConn(1024).
WithTimeOut(30*time.Second).
Build()
如果说config模式的实现还确实有些不够专业的话,builder模式已经足够好了。作者看这个builder对象不顺眼,但是个人感觉没啥问题,也不用为了宣扬一种设计模式而贬低另外一种。
3.FUNCTIONAL OPTIONS模式
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
}
}
s1, _ := NewServer("localhost", 1024)
s2, _ := NewServer("localhost", 2048, Protocol("udp"))
s3, _ := NewServer("0.0.0.0", 8080, Timeout(300*time.Second), MaxConns(1000))
解决了使用 Config 对象方式 的需要有一个config参数,但在不需要的时候,是放 nil 还是放
Config{}的选择困难,也不需要引用一个Builder的控制对象,直接使用函数式编程的试,在代码阅读上也很优雅