这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战
作者:lomtom
个人网站:lomtom.cn
个人公众号:博思奥园
你的支持就是我最大的动力。
Go系列:
- Go(一)基础入门
 - Go(二)结构体
 - Go(三)Go配置文件
 - Go(四)Redis操作
 - Go(五)Go不知道怎么用Gorm?
 - Go(六)来来来,教你怎么远程调用
 - Go(七)你说你不会并发?
 - Go(八)还不知道函数式选项模式?
 
引入
为option 结构体进行初始化,因为其是私有的,即只能包内访问,所以需要编写一个构造函数。
1  | go复制代码type option struct {  | 
构造函数
1  | Go复制代码func newOption(a, b string, c int) *option {  | 
使用的时候,直接调用该方法即可。
1  | go复制代码option := newOption("a","b",10)  | 
这样的代码看起来是没有问题的,并且使用起来也是非常方便的。
但是,如果此时需求发生变化,我不再需要三个参数的option,我只需要两个或者一个参数的option,怎么办呢?
而恰好Go语言不支持方法的重载,如果需要为一个结构体写多个初始化的构造函数,相同的方法名,不同的参数,这样的情况是不允许的,但往往这样情况的使用场景还是挺多的。
那么怎么办呢,只能在编写一个构造方法,并且命名为newOption1。
1  | go复制代码func newOption1(a, b string) *option {  | 
这样一看,确实没问题,也满足了我们的需求,但是谁也不敢保证日后需求不再发生变动。
那么选项模式的优势就来了。
选项模式进行初始化
选项模式利用闭包以及不定参数来达到参数的可选。
1  | go复制代码type OptionFunc func(*option)  | 
首先自定义一个函数类型,函数的参数是*option,并且为三个参数编写该选项方法。
1  | Go复制代码func newOption(opts... OptionFunc)(opt *option) {  | 
修改其构造方法,这样将每一个参数都作为一个选项进行初始化,如果没有传入该参数的选项,即保留默认值。
1  | Go复制代码func TestGo7(t *testing.T) {  | 
使用上,对结构体进行初始化时,可以选择初始化其一部分参数。
选项模式在Gorm中的应用
选项模式除了在结构体的初始化,还可以应用到哪方面呢?
恰好,对于数据库的查询操作往往也适合,在查询时,我们可能需要多个条件进行筛选,如果每种情况都写一个查询方法,不仅会使代码看起来很凌乱,并且写得多了,自己逻辑叶会变得很凌乱。
例如,这有一个字典表,拥有很多属性,如果对每个属性都需要进行筛选,那么情况就会有很多种,而利用选项模式只需要对每个字段编写一个选项即可完成多条件筛选。
1  | go复制代码// DataDictionary [...]  | 
编写自定义方法,编写options结构体用于存储选项关系。
1  | go复制代码type options struct {  | 
对DataType字段和DataKey字段编写查询选项方法。
1  | go复制代码/**************************************** 选项模式 ***********************************************************/  | 
编写查询方法,并且将选项遍历放入最开始定义的结构体options中。
1  | go复制代码// GetByOption 功能选项模式获取  | 
使用上直接将选项作为参数传入即可
1  | go复制代码res, _:= c.GetByOption(c.WithDataType("position"))  | 
这里你可能会纳闷,直接将options.query传入where为什么可以?
上面我们定义了options.query为map[string]interface{},我们点进Where方法源码中的tx.Statement.BuildCondition(query, args...)就可以看到,gorm会对参数进行类型判断,并且转换为sql。
1  | go复制代码switch v := arg.(type) {  | 
参考:
golang中函数类型
Go语言设计模式之函数式选项模式
Functional Options Pattern in Go
选项模式(option)
本文转载自: 掘金