Introducing problems: a conventional structure, then declare a constructor method for initializing the structure, the structure of the field for the assignment
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)
}
Common method to achieve
Each of the field declaration structure, and were compared to at construction fields and location of the structural body
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)
}
The problem with this approach: When the structure of each additional fields need to be modified on the line of the constructor, and the uncertainty of the structure increases the number of fields and field types, if you want to modify this approach of looking at the more cumbersome but looking at the code is relatively low
The second longhand
Type and number of fields of view field above wording is uncertain, we can become a variable parameter configured transmission mode parameters, a parameter is passed and interface
type, then a parameter by traversing the structure assignment
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)
}
This approach is also looking at more complicated, but we identified the number and types of arguments constructor requires is uncertain, then we introduced the option to transform design patterns
Options design pattern
- Declare a
Option
variable type, and function as a type, a function pointer type receiving typeOptions
structure - Constructor takes a variable-length
Option
variable type - After not add a field to create a specified format type of function, passing the constructor to initialize structure
code show as below:
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)
}