Golang编程模式:函数式编程(function options)
1.配置选项问题
1. golang编程时 我们经常需要对一个对象或者业务实体进行相关的配置 对相应的结构体进行初始化, 下面是结构题例子
type Server struct {
Addr string
Port int
Protocol string
Timeout time. Duration
MaxConns int
TLS * tls. Config
}
1.1 我们对结构题初始化赋值,可能会考虑
1.2 sever监听的Addr和Port不能为空
1.3 其它字段比如协议 Protocol可以默认TCP 最大连接数MaxConns默认1024 等
1.4 TLS安全连接可以为nil
2.针对上述情况 我们需要多种不同的创建配置
2.1 . 比如地址端口必须 就创建
func NewDefaultServer ( addr string , port int ) * Server{
return & Server{ addr, port, "tcp" , 30 * time. Second, 100 , nil }
}
2.2 . 配置TLS
func NewTLSServer ( addr string , port int , tls * tls. Config) * Server {
return & Server{ addr, port, "tcp" , 30 * time. Second, 100 , tls}
}
2.3 . 配置timeout
func NewServerWithTimeout ( addr string , port int , timeout time. Duration) * Server {
return & Server{ addr, port, "tcp" , timeout, 100 , nil }
}
2.4 . 配置更多的参数
func NewTLSServerWithMaxConnAndTimeout ( addr string , port int , maxconns int , timeout time. Duration, tls * tls. Config) * Server {
return & Server{ addr, port, "tcp" , 30 * time. Second, maxconns, tls}
}
go 语言不支持重载函数 不同的函数名对应不同的配置项,这样就会容易犯错
3.优化方式例如下面所示
3.1 . 将变动的参数放到同一结构体 这样代码就看起来简洁多了
type Server struct {
Addr string
Port int
Conf * Config
}
type Config struct {
Protocol string
Timeout time. Duration
Maxconns int
TLS * tls. Config
}
func NewServer ( addr string , port int , conf * Config) * Server {
}
srv1, _ := NewServer ( "localhost" , 9000 , nil )
conf := Config{ Protocol: "tcp" , Timeout: 60 * time. Duration}
srv2, _ := NewServer ( "locahost" , 9000 , & conf)
3.2 . 但是上面的优化还不够装杯,后来我们在看源码(比如gin 比如mq)的时候会看到函数式编程
那就让我们看看什么是函数式编程,以后出去好装杯,当然更重要的是提升我们的代码能力
4.函数式编程
4.1 . 定义新函数类型
type Option func ( * Server)
4.2 . 使用函数式的方式定义一组函数
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
}
}
4.3 . 这样的函数简介明了 传入一个参数 通过返回的函数设置自己的server参数
4.4 . 例如我们调用MaxConns ( 30 ) 返回值是一个 func ( s * Server) { s. MaxConns = 30 } 的函数
4.5 . 现在我们在定义一个整体的NewServer函数,加上一个可变传参options
func NewServer ( addr string , port int , options ... Option) * Server {
server := Server{
Addr: addr,
Port: port,
Protocol: "tcp" ,
Timeout: 30 * time. Second,
MaxConns: 1000 ,
TLS: nil ,
}
for _ , option := range options {
option ( & srv)
}
return & server
}
4.6 . 再初始化的时候就简洁明了,用什么拿什么
s1, _ := NewServer ( "localhost" , 1024 )
s2, _ := NewServer ( "localhost" , 2048 , Protocol ( "udp" ) )
s3, _ := NewServer ( "0.0.0.0" , 8080 , Timeout ( 300 * time. Second) , MaxConns ( 1000 ) )
总结
这就是函数式编程 使得开发更简单 用什么拿什么 新手来了也不会纠结怎么定义新配置函数名称 直接用就行