Golang 选项设计模式
引入问题: 现有一个结构体,再声明一个用于初始化该结构体的构造方法, 进行对结构体字段赋值
package main
import "fmt"
// 声明options结构体
type Options struct {
str1 string
str2 string
int1 int
int2 int
}
// 声明构造方法进行初始化结构体
func InitOptions() *Options {
return &Options{}
}
func main() {
options := InitOptions()
fmt.Printf("%#v", options)
}
普通方法实现
在构造方法中声明结构体的每一个字段值,且要和结构体中的字段位置进行对照
package main
import "fmt"
// 声明options结构体
type Options struct {
str1 string
str2 string
int1 int
int2 int
}
// 声明构造方法进行初始化结构体
func InitOptions(str1 string, str2 string, int1 int, int2 int) *Options {
options := &Options{}
options.str1 = str1
options.str2 = str2
options.int1 = int1
options.int2 = int2
return options
}
func main() {
options := InitOptions("a", "b", 1, 2)
fmt.Printf("%#v", options)
}
此方法的问题: 当结构体每增加一个字段都需要进行对构造函数就行修改,并且对结构体字段增加的个数和字段类型具有不确定性,如果要修改的化这种方法看着比较繁琐,而且代码看着也比较 low
第二种普通写法
看上面的写法字段的个数和字段的类型都是不确定的,我们可以将构造参数变为一个可变的传参方式,并且传入的参数是一个 interface
类型的,之后通过遍历参数给结构体赋值
package main
import "fmt"
// 声明options结构体
type Options struct {
str1 string
str2 string
int1 int
int2 int
}
// 声明构造方法进行初始化结构体
func InitOptions(opts ...interface{}) *Options {
options := &Options{}
for index, val := range opts {
switch index {
case 1:
v, _ := val.(string)
options.str1 = v
case 2:
v, _ := val.(string)
options.str2 = v
case 3:
v, _ := val.(int)
options.int1 = v
case 4:
v, _ := val.(int)
options.int2 = v
}
}
return options
}
func main() {
options := InitOptions("a", "b", 1, 2)
fmt.Printf("%#v", options)
}
这种方法看着也是比较繁琐,但是我们确定了构造函数需要的参数个数和类型是不确定的,那我们就引入使用选项设计模式进行改造
选项设计模式实现
- 声明一个
Option
变量类型,类型为一个函数类型,函数类型接收一个指针类型的Options
结构体 - 构造函接受一个可变长度的
Option
变量类型 - 之后没增加一个字段创建一个指定格式类型的函数,传入构造函数即可初始化结构体
代码如下:
package main
import "fmt"
// 声明options结构体
type Options struct {
str1 string
str2 string
int1 int
int2 int
}
// 声明一个变量类型,变量接收一个Options结构体的指针类型
type Option func(opts *Options)
// 声明构造方法进行初始化结构体
func InitOptions(opts ...Option) *Options {
options := &Options{}
for _, opt := range opts {
opt(options)
}
return options
}
func WithOptionStr1(str string) Option {
return func(opts *Options) {
opts.str1 = str
}
}
func WithOptionStr2(str string) Option {
return func(opts *Options) {
opts.str2 = str
}
}
func WithOptionInt1(i int) Option {
return func(opts *Options) {
opts.int1 = i
}
}
func WithOptionInt2(i int) Option {
return func(opts *Options) {
opts.int2 = i
}
}
func main() {
options := InitOptions(
WithOptionStr1("a"),
WithOptionStr2("b"),
WithOptionInt1(1),
WithOptionInt2(2),
)
fmt.Printf("%#v", options)
}