由于Golang不支持函数重载,因此无法像C++或Java那样可以定义多个同名不同参的构造函数,因此如果要定义多个构造函数就需要使用不同的名称。但是如果后续要给结构体增加新的字段,那么可能就需要修改很多的构造函数,函数选项模式就可以完美解决这个问题。
1、正常的构造函数
拿下面的代码举个例子:
type User struct {
username string
password string
nickname string
age uint8
gender bool
address string
email string
}
func NewUser(username, password, nickname, address, email string, age uint8, gender bool) *User {
return &User {
username: username,
...
}
}
u := NewUser("zhangsan", "fawaikuangtu", "", "", "", 0, false)
func NewUserSimple(username, password string) *User {
return &User {
username: username,
password: password,
}
}
type User struct {
username string
password string
nickname string
age uint8
gender bool
address string
email string
phoneNum string
}
func (u *User) GetPhoneNum() string {
return u.phoneNum
}
func (u *User) SetPhoneNum(pnum string) {
u.phoneNum = pnum
}
u := NewUser("zhangsan", "fawaikuangtu", "", "", "", 0, false)
u.SetPhoneNum("911")
u := NewUser("zhangsan", "fawaikuangtu", "", "", "", 0, false)
u.PhoneNum = "911"
2、函数选项模式
接下来使用函数选项模式来实现构造函数:
type User struct {
username string
password string
nickname string
age uint8
gender bool
address string
email string
}
type OptionFunc func(u *User)
func NewUser(username, password string, options ...OptionFunc) *User {
u := &User{
username: username,
password: password,
}
for _, o := range options {
o(u)
}
if u.age == 0 {
u.age = 18
}
...
return u
}
func WithNickname(nickname string) OptionFunc {
return func(u *User) {
u.nickname = nickname
}
}
func WithAge(age uint8) OptionFunc {
return func(u *User) {
u.age = age
}
}
...
func WithEmail(email string) OptionFunc {
return func(u *User) {
u.email = email
}
}
u := NewUser("zhangsan", "fawaikuangtu", WithNickname("luoxiang"), WithEmail("kuangtu@qq.com"))
当然,也有一些其他的方式,比如下面的方式:
type User struct {
username string
password string
nickname string
age uint8
gender bool
address string
email string
}
func NewUser(username, password string) *User {
return &User{
username: username,
password: password,
}
}
func (u *User) Nickname(nickname string) *User {
u.nickname = nickname
return u
}
...
func (u *User) Address(addr string) *User {
u.address = addr
return u
}
func (u *User) Email(email string) *User {
u.email = email
return u
}
u := NewUser("zhangsan", "fawaikuangtu").Nickname("luoxiang").Email("kuangtu@qq.com")
总结:函数选项模式在一些场景下可以很好地解决golang不支持函数重载的问题,但是在一些比较简单的场景下,比如只有两三个甚至一个构造函数的情况下,完全没有必要使用函数选项模式,直接写不同名的构造函数即可。但是在参数复杂同时一些参数又会有默认值的情况下,就可以使用函数选项模式,在很多的开源库中,函数选项模式也有使用,在大多数场景下用于一些基础的配置,比如Mysql、Redis等。
函数选项模式的优点:
- 支持任意顺序的参数传递
- 易于扩展,新增字段时,只需新增一个函数即可
- 支持默认值的设置
缺点: