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)
}

这种方法看着也是比较繁琐,但是我们确定了构造函数需要的参数个数和类型是不确定的,那我们就引入使用选项设计模式进行改造

选项设计模式实现

  1. 声明一个 Option 变量类型,类型为一个函数类型,函数类型接收一个指针类型的 Options 结构体
  2. 构造函接受一个可变长度的 Option 变量类型
  3. 之后没增加一个字段创建一个指定格式类型的函数,传入构造函数即可初始化结构体

代码如下:

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)
}
posted @ 2020-03-17 10:40  ZhiChao&  阅读(751)  评论(0编辑  收藏  举报