选项(Option)设计模式

设计模式的出现,是为了解决编程中遇到的一些问题,现在有一个场景:

我们需要初始化一个服务的配置文件,比如是这样:

type Config struct {
	id   int
	name string
	ip   string
	port string
	// other params ...
}

常见的初始化,有以下几种:

方式一:

func initConfig(id int, name, ip, port string) {
	conf.id = id
	conf.name = name
	conf.ip = ip
	conf.port = port
}

这种方式,参数比较固定,比如我以后想扩展一些参数是很吃力的,而且,参数的位置也比较固定,就是说这个函数一旦开始被使用,参数位置就不能随意更改了,非常不灵活。

注意,可变参数(params ...interface{})也是一样,不能解决根本问题,参数位置还是固定的,而且函数内部还需要断言处理。

有些同学说,那我传个结构体不就行了吗,就不用考虑扩展参数和参数顺序问题了,于是就有了下一种方式:

方式二:

func initConfig(c Config) {
	conf.id = c.id
	conf.name = c.name
	conf.ip = c.ip
	conf.port = c.port
}

这种方式确实解决了以上两个问题,但是也把所有配置全部暴露出去了,不但破坏了程序的封装性,而且,如果我想要一些默认的初始化,比如端口号默认8000,外部支持缺省配置,这又成问题了,于是又有了另一种方式:

方式三:

func setId(id int)  {
	conf.id = id
}

func setName(name string)  {
	conf.name = name
}

...

这种方式确实解决了以上问题,但是也产生了新的问题,随着参数的扩展,程序中的setXXX(或initXXX)方法也逐渐增加,而且,参数设置被分的很零散,不便于程序管理,再比如这时候想做个初始化统计,这种也是很繁琐,等等诸多问题。

=================

综上,那有没有一种方式,能够支持缺省配置,也能够在参数上随意的更换位置,初始化配置也不要调那么分散,能解决以上的这些问题呢?

于是,就有了option模式:

我这里先提供一个定义示例:

type Option func(opt *options)

type options struct {
	id   int
	name string
	ip   string
	port string
	// other params ...
}

func WithId(id int) Option {
	return func(opt *options) {
		opt.id = id
	}
}

func WithName(name string) Option {
	return func(opt *options) {
		opt.name = name
	}
}

然后是设置:

var conf = &options{
	port: "8000",
}

func Parse(opt ...Option) {
	for _, o := range opt {
		o(conf)
	}
}

这就达到想要的效果了,需要扩展参数的时候,如果想对外暴露,就添加对应的With方法就可以了。

最后看一下使用:

func main() {
	Parse(WithName("testName"), WithId(1000))
}

使用也很简洁,每一个参数都是Option类型,参数数量和顺序都可以随意控制,达到了想要的效果!

 

 


版权声明:本文为u011859715原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。