Go语言的Optional设计模式
引言
在很多情况下,我们都需要实现一些结构体去实现功能或者作为程序的核心,但是结构体的初始化方法是一个很大的问题,例如,当一个结构体拥有很多字段,而我们在实现结构体的过程中可能需要传入非常多的参数,这样对我们的记忆有很大的考验而且不易于维护。
在这种情况下,程序员们想出了一个更好的解决方案:config
模式,也就是构造一个和结构体字段相同或相似的config结构体,初始化结构体的时候只需要传入构造好的config即可,这样带来了很大便利,也是很多著名项目的解决方案,例如go-redis
。同时也带来一个新的问题,当我们需要改变一个字段的名称时,用户端的字段就要相应的改变,这样给用户带去了很多不便,于是,Optional设计模式应运而生。
Optional模式
Option模式的专业术语为:Functional Options Pattern(函数式选项模式) Option模式为golang的开发者提供了将一个函数的参数设置为可选的功能,也就是说我们可以选择参数中的某几个,并且可以按任意顺序传入参数。 比如针对特殊场景需要不同参数的情况,C++可以直接用重载来写出任意个同名函数,在任意场景调用的时候使用同一个函数名即可;但同样情况下,在golang中我们就必须在不同的场景使用不同的函数,并且参数传递方式可能不同的人写出来是不同的样子,这将导致代码可读性差,维护性差。
Optional的简单实现
package main
import (
"fmt"
"time"
)
type Server struct {
Addr string
Port int
Protocol string
Timeout time.Duration
}
type Option func(*Server)
func WithAddr(addr string) Option {
return func(server *Server) {
server.Addr = addr
}
}
func WithPort(port int) Option {
return func(server *Server) {
server.Port = port
}
}
func WithProtocol(protocol string) Option {
return func(server *Server) {
server.Protocol = protocol
}
}
func WithTimeout(timeout time.Duration) Option {
return func(server *Server) {
server.Timeout = timeout
}
}
func NewServer(options ...Option) *Server {
s := &Server{}
for _, o := range options {
o(s)
}
return s
}
func main() {
s1 := NewServer(WithAddr("localhost"), WithPort(80))
s2 := NewServer(WithAddr("localhost"), WithPort(8080), WithProtocol("HTTP"))
s3 := NewServer(WithAddr("localhost"), WithPort(8080), WithProtocol("HTTP"), WithTimeout(time.Hour))
fmt.Println(s1)
//&{localhost 80 0s}
fmt.Println(s2)
//&{localhost 80 0s}
fmt.Println(s3)
//&{localhost 8080 HTTP 1h0m0s}
}
这样我们就实现了一个简单的Optional设计。
Optional的优缺点
优点
- 任意顺序传递参数
- 支持传递多个参数,并且在参数个数、类型发生变化时保持兼容性
缺点
- 增加许多function,成本增大