我啥介绍Golang Option范式呢? 如果熟悉 containerd 代码就会发现,containerd里面大量地使用了这种编程范式,因为启动容器的参数非常多而且还有关联。它的主要场景就是优雅地设置复杂的各种关联属性,下面通过代码演示一下。
我们先定义一个简单的User 结构体
type User struct {
Name string
Role string
MinSalary int
MaxSalary int
}
通常我们会定义一个NewUser 方法去初始化这个结构体,返回一个指针,但我们这里需要各种自定义参数设置。比如,当我们定义这个用户的角色是 “经理” 的时候,那么他的薪资也需要设置成相应的值。
我们可以这样玩
先定义一个 UserOption 方法,方法只有一个参数,就是我们需要设置的 user。
type UserOption func(user *User) error
然后定义一个方法 遍历每一个 UserOption ,执行UserOption 方法。
func BuildUser(opts ...UserOption) (*User, error) {
var user User
for _, opt := range opts {
err := opt(&user)
if err != nil {
return nil, err
}
}
return &user, nil
}
这样,这个user 就可以被每个 UserOption 都改一遍了。
最后我们去实现两个 UserOption 测试一下
第一个 UserOption,非常简单,就是设置user name。
func WithName(name string) UserOption {
return func(user *User) error {
user.Name = name
return nil
}
}
第二个 UserOption ,如果是 经理 则设置薪资范围,如下;
func WithRole(role string) UserOption {
return func(user *User) error {
// 校验角色
if role != "manager" && role != "sales" {
return errors.New("Invalid role!")
}
if role == "manager" {
user.MinSalary = 40000
user.MaxSalary = 60000
}
user.Role = role
return nil
}
}
最最后,在main里面就可以优雅地使用下面的方法创建一个复杂的 user 了。
func main() {
user, err := BuildUser(
WithName("Michael Scott"),
WithRole("manager"),
)
if err != nil {
panic(err)
}
fmt.Println(user)
}
大家都学会了吗 ?