一种很优雅的选项配置实现

267 阅读2分钟

这种实现的优点是:输入的各种配置,可以选择不传入,不传入则使用默认配置;选择传入,则调用可视化的方法明确指定要设置的配置,比较优雅,而且不要求传入的顺序固定。缺点就是底层方法要多写一些代码,但是这样整体结构比较好看高级

以log初始化需要传入的配置为例

首先把所有需要配置的变量放在一个结构体里

type options struct {
	path    string
	level   string
	isDebug bool
}

声明各个配置项的默认值

const (
	defaultPath    = "../log/default.log"
	defaultLevel   = "DEBUG"
	defaultIsDebug = false
)

声明一个接口Option,内部有一个方法apply

再声明一个变量optionFunc ,实现这个接口,实现的方法很简单,实现apply方法即可

这里注意变量optionFunc是一个函数,他的apply方法内部逻辑就是把apply的参数当作自己的入参,具体做什么要看具体的optionFunc

type Option interface {
	apply(*options)
}

type optionFunc func(*options)

// apply 的功能就是把o传给方法f,至于具体做什么,要看具体的方法,比如WithPath,就是修改o的属性path
func (f optionFunc) apply(o *options) {
	f(o)
}

下面实现各个配置对应的方法,返回的都是接口类型,内部实际返回的是optionFunc类型的方法,方法内部的逻辑都不同,比如WithLevel 返回的方法就是修改传入的参数options的level变量

注意这个的options传的是指针,这样修改才能生效

func WithPath(path string) Option {
	return optionFunc(func(o *options) {
		o.path = path
	})
}

func WithLevel(level string) Option {
	return optionFunc(func(o *options) {
		o.level = level
	})
}

func WithIsDebug(isDebug bool) Option {
	return optionFunc(func(o *options) {
		o.isDebug = isDebug
	})
}

使用场景

type Connection struct {
   addr    string
   cache   bool
   timeout time.Duration
}
func NewConnect(addr string, opts ...Option) (*Connection, error) {
   //首先创建默认配置
   options := options{
      timeout: defaultTimeout,
      caching: defaultCaching,
   }
   for _, o := range opts {
      o.apply(&options)
   }

   return &Connection{
      addr:    addr,
      cache:   options.caching,
      timeout: options.timeout,
   }, nil
}

func testConnect(){
   NewConnect("localhost:1220",WithCaching(false),WithTimeout(3*time.Second))
}

这也是设计模式里面的选项模式

image.png