Appearance
Go Options 模式
1. Options 模式
通过 Options 模式您可以在其中声明一个不透明 Option 类型,该类型在某些内部结构中记录信息。您接受这些选项的可变编号,并根据内部结构上的选项记录的全部信息采取行动。
将此模式用于您需要扩展的构造函数和其它公共 API 中的可选参数,尤其是在这些功能上已经具有三个或更多参数的情况下。
| Bad | Good |
|---|---|
Go 1 2 3 4 5 6 7 8 9 | Go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
必须始终提供缓存和记录器参数,即使用户希望使用默认值。 Go 1 2 3 4 | 只有在需要时才提供选项。 Go 1 2 3 4 5 6 7 8 |
我们建议实现此模式的方法是使用一个 Option 接口,该接口保存一个未导出的方法,在一个未导出的 options 结构上记录选项。
Go
type options struct {
cache bool
logger *zap.Logger
}
type Option interface {
apply(*options)
}
type cacheOption bool
func (c cacheOption) apply(opts *options) {
opts.cache = bool(c)
}
func WithCache(c bool) Option {
return cacheOption(c)
}
type loggerOption struct {
Log *zap.Logger
}
func (l loggerOption) apply(opts *options) {
opts.logger = l.Log
}
func WithLogger(log *zap.Logger) Option {
return loggerOption{Log: log}
}
// Open creates a connection.
func Open(
addr string,
opts ...Option,
) (*Connection, error) {
options := options{
cache: defaultCache,
logger: zap.NewNop(),
}
for _, o := range opts {
o.apply(&options)
}
// ...
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
注意:还有一种使用闭包实现这个模式的方法,但是我们相信上面的模式为作者提供了更多的灵活性,并且更容易对用户进行调试和测试。特别是,在不可能进行比较的情况下它允许在测试和模拟中对选项进行比较。此外,它还允许选项实现其它接口,包括 fmt.Stringer,允许用户读取选项的字符串表示形式。
还可以参考下面资料:
2. Functional Options 模式
Go
type User struct {
Name string
Age int
Email string
Phone string
//...Other
School string
Gender string
}
type UserOption func(*User)
func WithPhone(phone string) UserOption {
return func(user *User) {
user.Phone = phone
}
}
func WithSchool(school string) UserOption {
return func(user *User) {
user.School = school
}
}
func WithGender(gender string) UserOption {
return func(user *User) {
user.Gender = gender
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
使用时通过遍历 UserOption 可变参数来设置 User 对象:
Go
func CreateUser(name string, age int, email string, opt ...UserOption) User {
user := User{Name: name, Age: age, Email: email}
for _, option := range opt {
option(&user)
}
return user
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9