一文带你搞懂Go语言函数选项模式,Go函数一等公民。
前言
通过这篇文章《为什么说Go的函数是”一等公民“》,我们了解到了什么是“一等公民”,以及都具备哪些特性,同时对函数的基本使用也更加深入。
本文重点介绍下Go设计模式之函数选项模式,它得益于Go的函数是“一等公民”,很好的一个应用场景,广泛被使用。
什么是函数选项模式
函数选项模式(Functional Options Pattern) ,也称为选项模式(Options Pattern),是一种创造性的设计模式,允许你使用接受零个或多个函数作为参数的可变构造函数来构建复杂结构。我们将这些函数称为选项,由此得名函数选项模式。
看概念有点太生硬难懂了,下面通过例子来讲解下怎么使用,由浅入深,通俗易懂。
怎么使用函数选项模式
一般水平
先来一个简单例子,这个Animal结构体
,怎么构造出一个实例对象
type Animal struct {Name stringAge intHeight int
}
通常的写法:
func NewAnimal(name string, age int, height int) *Animal {return &Animal{Name: name,Age: age,Height: height,}
}a1 := NewAnimal("小白兔", 5, 100)
简单易懂,结构体有哪些属性字段,那么构造函数的参数,就相应做定义并传入
带来的问题:
- 代码耦合度高:加属性字段,构造函数就得相应做修改,调用的地方全部都得改,势必会影响现有代码;
- 代码灵活度低:属性字段不能指定默认值,每次都得明确传入;
例如,现计划新加3个字段Weight体重
、CanRun是否会跑
、LegNum几条腿
,同时要指定默认值CanRun=true、LegNum=4
新结构体定义:
type Animal struct {Name stringAge intHeight intWeight intCanRun boolLegNum int
}
代码实现(函数加新参数定义,但默认值貌似实现不了,得调用构造函数时,明确传入):
func NewAnimal(name string, age int, height int, weight int, canRun bool, legNum int) *Animal {return &Animal{Name: name,Age: age,Height: height,Weight: weight,CanRun: canRun,LegNum: legNum,}
}a1 := NewAnimal("小白兔", 5, 100, 120, true, 4)
后续逐步加新字段,这个构造函数就会被撑爆了,如果调用的地方越多,那么越伤筋动骨。
高阶水平
既然常规写法太low,难以实现新需求,那么我们就来玩点高阶的,引出主题:函数选项模式
首先,需要先定义一个函数类型OptionFunc
type OptionFunc func(*Animal)
然后,根据新结构体字段,定义With开头
的函数,返回函数类型为OptionFunc
的闭包函数,内部逻辑只需要实现更新对应字段值即可
func WithName(name string) OptionFunc {return func(a *Animal) { a.Name = name }
}func WithAge(age int) OptionFunc {return func(a *Animal) { a.Age = age }
}func WithHeight(height int) OptionFunc {return func(a *Animal) { a.Height = height }
}func WithWeight(weight int) OptionFunc {return func(a *Animal) { a.Weight = weight }
}func WithCanRun(canRun bool) OptionFunc {return func(a *Animal) { a.CanRun = canRun }
}func WithLegNum(legNum int) OptionFunc {return func(a *Animal) { a.LegNum = legNum }
}
再然后,优化构造函数的定义和实现(name作为必传参数,其他可选,并且实现CanRun
和LegNum
两个字段指定默认值)
func NewAnimal(name string, opts ...OptionFunc) *Animal {a := &Animal{Name: name, CanRun: true, LegNum: 4}for _, opt := range opts {opt(a)}return a
}
最后,调用优化后的构造函数,快速实现实例的初始化。想要指定哪个字段值,那就调用相应的With开头
的函数,完全做到可配置化、可插拔;不指定还支持了默认值
a2 := NewAnimal("大黄狗", WithAge(10), WithHeight(120))
fmt.Println(a2)
a3 := NewAnimal("大灰狼", WithHeight(200))
fmt.Println(a3)输出结果:
&{大黄狗 10 120 0 true 4}
&{大灰狼 0 200 0 true 4}
带来的好处:
- 高度的可配置化、可插拔,还支持默认值设定;
- 很容易维护和扩展;
- 容易上手,大幅降低新来的人试错成本;
开源项目中的实践案例
函数选项模式,不单单是我们业务代码中有使用,现在大量的标准库和第三库都在使用。
下面带着大家一块来看看,apollo配置中心客户端第三库shima-park/agollo,看看它是怎么玩的,怎么做配置初始化
核心代码:
type Options struct {AppID string // appidCluster string // 默认的集群名称,默认:defaultDefaultNamespace string // Get时默认使用的命名空间,如果设置了该值,而不在PreloadNamespaces中,默认也会加入初始化逻辑中PreloadNamespaces []string // 预加载命名空间,默认:为空ApolloClient ApolloClient // apollo HTTP api实现Logger Logger // 日志实现类,可以设置自定义实现或者通过NewLogger()创建并设置有效的io.Writer,默认: ioutil.DiscardAutoFetchOnCacheMiss bool // 自动获取非预设以外的Namespace的配置,默认:falseLongPollerInterval time.Duration // 轮训间隔时间,默认:1sBackupFile string // 备份文件存放地址,默认:.agolloFailTolerantOnBackupExists bool // 服务器连接失败时允许读取备份,默认:falseBalancer Balancer // ConfigServer负载均衡EnableSLB bool // 启用ConfigServer负载均衡RefreshIntervalInSecond time.Duration // ConfigServer刷新间隔ClientOptions []ApolloClientOption // 设置apollo HTTP api的配置项EnableHeartBeat bool // 是否允许兜底检查,默认:falseHeartBeatInterval time.Duration // 兜底检查间隔时间,默认:300s
}func newOptions(configServerURL, appID string, opts ...Option) (Options, error) {var options = Options{AppID: appID,Cluster: defaultCluster,ApolloClient: NewApolloClient(),Logger: NewLogger(),AutoFetchOnCacheMiss: defaultAutoFetchOnCacheMiss,LongPollerInterval: defaultLongPollInterval,BackupFile: defaultBackupFile,FailTolerantOnBackupExists: defaultFailTolerantOnBackupExists,EnableSLB: defaultEnableSLB,EnableHeartBeat: defaultEnableHeartBeat,HeartBeatInterval: defaultHeartBeatInterval,}for _, opt := range opts {opt(&options)}//...省略return options, nil
}type Option func(*Options)//一系列函数作为选项
func PreloadNamespaces(namespaces ...string) Option {return func(o *Options) {o.PreloadNamespaces = append(o.PreloadNamespaces, namespaces...)}
}
func AutoFetchOnCacheMiss() Option {return func(o *Options) {o.AutoFetchOnCacheMiss = true}
}
//...
玩法:
- 使用Options结构体,定义出apollo需要使用到的所有配置字段;
- 定义一系列函数作为选项,对配置字段做初始化设置(例如,设置容灾文件路径、预加载的namespace、轮训间隔时间等等);
- 构造函数里初始化一个Options的实例对象,并且根据传入的函数选项,进行配置字段的更新,最终返回这个实例对象;
- 获取到实例对象,调用相应的方法做相应的操作。
总结
由浅入深的讲解了下实例对象初始化一般写法和高阶写法。用好这个高阶写法(函数选项模式),让代码更高比格。还不会使用的Gopher,赶紧学起来,用起来。
文章首发
我的文章会首发在我的公众号:程序员升职加薪之旅,欢迎大家关注,第一时间收到最新内容。
一起学习
我的所有文章都会首发在我的 学习小圈子 ,欢迎加入我们,一起学习进步,一起升职加薪。
相关文章:
一文带你搞懂Go语言函数选项模式,Go函数一等公民。
前言 通过这篇文章《为什么说Go的函数是”一等公民“》,我们了解到了什么是“一等公民”,以及都具备哪些特性,同时对函数的基本使用也更加深入。 本文重点介绍下Go设计模式之函数选项模式,它得益于Go的函数是“一等公民”&#…...
Window.location 详细介绍
如果你需要获取网站的 URL 信息,那么 window.location 对象就是为你准备的。使用它提供的属性来获取当前页面地址的信息,或使用其方法进行某些页面的重定向或刷新。 https://www.samanthaming.com/tidbits/?filterJS#2 window.location.origin → htt…...
js侧滑显示删除按钮
效果图: <!DOCTYPE html> <html><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno"><title>js侧滑显示删…...
Python - DIY - 使用dump取json某些键值对合成新的json文件
Python - Json处理前言:应用场景:基本工具:文件操作:打开文件:写文件:读文件:关闭文件并刷新缓冲区:Json字符串和字典转换:json.loads():json.dumps():Json文…...
深度剖析指针(中)——“C”
各位CSDN的uu们你们好呀,今天小雅兰的内容仍旧是深度剖析指针噢,在上一篇博客中,我已经写过了字符指针、数组指针、指针数组、数组传参和指针传参的知识点,那么这篇博客小雅兰会讲解一下函数指针、函数指针数组 、指向函数指针数组…...
论文阅读 | Video Frame Synthesis using Deep Voxel Flow
前言: 视频帧生成方法(视频插帧/视频预测)ICCV2017 oral Video Frame Synthesis using Deep Voxel Flow 引言 当下进行视频帧合成的方法分为两种,第一种是光流法,光流准确的话效果好,光流不准确的话则生…...
我所理解的生活
诞生 人真正意义上的诞生应该是社会学意义上的,是一种意识到自我、自我与社会关系的存在,只有这种诞生,才是完整人生的基点,大千世界中,唯有人类以生活作为自己的存在方式,除人类以外,从无机界…...
debian 部署nginx https
我是flask 处理请求单进程, 差点意思 , 考虑先flask 在往下走 一:安装nginx 因为我是debian 系统,所以我的建议是直接 sudo apt-get install nginx 你也可以选择在官网下载, 但是我搭建ssl 的时候安装openssl非常的麻…...
SQL 层功能改进 - lookupJoin 的优化
一、传统 join 算法lookupJoin 是 join 查询的一种,传统 join 算法为:1. 遍历 A 表,读取一条数据 r2. 遍历 B 表,对于每条数据,与 r 进行 join 操作3. 重复 1、2 操作,直到 A 表遍历完所有数据二、lookupJo…...
动态规划:鸣人的影分身
在火影忍者的世界里,令敌人捉摸不透是非常关键的。我们的主角漩涡鸣人所拥有的一个招数——多重影分身之术——就是一个很好的例子。影分身是由鸣人身体的查克拉能量制造的,使用的查克拉越多,制造出的影分身越强。针对不同的作战情况…...
如何为三星active2手表安装自己DIY的表盘
一、步骤介绍 Step 1. 下载Galaxy watch studio; Step 2. 按照up主“隔壁张师傅2022”的文章进行安装。 二、安装流程简单说明: ① 电脑端官网下载并安装Galaxy Watch Designer或者Galaxy Watch Studio程序。 ② 关闭手表蓝牙连接,并打开调…...
Android 项目必备(四十二)-->Android 多窗口模式
简介 自由窗口模式: 该模式类似于常见的桌面操作系统, 应用界面的窗口可以自由的拖动和修改大小。 分屏模式 该模式可以在手机上使用, 该模式将屏幕一分为二, 同时显示两个应用界面。 画中画模式: 该模式主要用于TV, 在该模式下…...
OpenHarmony的未来和如何做好一个开源社区
今天要分享的文章,可能更多只是作为一种观点。主要包括2个内容。OpenHarmony的未来和如何做好一个开源社区,好的,接下来开始今天的内容。 你对OpenHarmony的未来如何看待? OpenHarmony的未来看起来非常光明,因为它具…...
二叉搜索树实现
树的导览 树由节点(nodes)和边(edges)构成,如下图所示。整棵树有一个最上端节点,称为根节点(root)。每个节点可以拥有具有方向的边(directed edges)…...
解决Spring Data Jpa 实体类自动创建数据库表失败问题
先说一下我遇到的这个问题,首先我是通过maven创建了一个spring boot的工程,引入了Spring data jpa,结果实体类创建好之后,运行工程却没有在数据库中自动创建数据表。 找了半天发现是一个配置的问题! hibernate.ddl-auto节点的配…...
Elasticsearch:创建一个简单的 “你的意思是?” 推荐搜索
“你的意思是” 是搜索引擎中一个非常重要的功能,因为它们通过显示建议的术语来帮助用户,以便他可以进行更准确的搜索。比如,在百度中,我们进行搜索时,它通常会显示一些更为常用推荐的搜索选项来供我们选择:…...
urllib之ProxyHandler代理以及CookieJar的cookie内存传递和本地保存与读取的使用详解
处理更高级操作时(Cookies处理,代理设置),需要一个强大的工具Handler,可以理解成各种处理器,有处理登录认证的、有处理Cookies的、有处理代理设置的。利用这些几乎可以做到HTTP请求中所有事情。当中urllib.request模块里的 BaseHa…...
华为造车锚定智选模式, 起点赢家赛力斯驶入新能源主航道
文|螳螂观察 作者| 易不二 近日,赛力斯与华为的一纸联合业务深化合作协议,给了频频猜测赛力斯与华为之间关系的舆论一个明确的定调:智选模式已成为华为与赛力斯共同推动中国新能源汽车产业高质量发展的坚定选择。 自华为智能汽车业务开启零…...
[oeasy]python0096_游戏娱乐行业_雅达利_米洛华_四人赛马_影视结合游戏
游戏娱乐行业 回忆上次内容 游戏机行业从无到有 雅达利 公司 一枝独秀并且带领 行业 发展起来 雅达利公司 优秀员工 乔布斯 在 朋友 帮助下完成了《pong》 Jobs 黑了 Woz 一部分收入 然后拿着钱 去印度禅修了 游戏行业 会如何继续 呢??🤔 灵修 乔布…...
使用python测试框架完成自动化测试并生成报告-实例练习
练习一: 使用unittest 完成自动化测试并使用HttpTestRunner生成报告 1、写个简单的计算器功能,大小写转换功能,随机生成字符串功能 2、编写测试用例,不同的数据(你能想到的所有测试用例),并进行断言。除0的…...
JavaWeb 实战 01 - 计算机是如何工作的
计算机是如何工作的1. 计算机发展史2. 计算机的基本组成2.1 冯诺依曼体系结构2.2 CPU的内部结构2.3 指令2.3.1 指令表2.3.1.1 寄存器2.3.2 CPU的工作流程2.4 小结3. 操作系统3.1 核心功能3.2 操作系统的软硬件结构3.3 什么是进程 / 任务3.4 进程管理3.4.1 管理3.4.2 PCB : 进程…...
线性代数学习-1
线性代数学习-1行图像和列图像行图像列图像总结本文转载于https://herosunly.blog.csdn.net/article/details/88698381 该文章本人认为十分有用,便自己敲一遍笔记加固印象原文链接 原文这个笔记感觉比我老师讲的更加透彻,清晰。很好的展示了线性代数的原…...
人工智能写的十段代码,九个通过测试了
“抢走你工作的不会是 AI ,而是先掌握 AI 能力的人” 编程测试 1. 我想用golang实现二叉树前序,请你帮我写一下代码。 // 定义二叉树节点 type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode }// 前序遍历 func PreOrderTraversal(root *Tre…...
巴塞尔问题数值逼近方法
巴塞尔问题:计算所有平方数的导数和 ∑n1∞1n2limn→∞(112122⋯1n2)\sum_{n1}^{\infty} \frac{1}{n^{2}}\lim _{n \rightarrow\infty}\left(\frac{1}{1^{2}}\frac{1}{2^{2}}\cdots\frac{1}{n^{2}}\right)n1∑∞n21n→∞lim(121221⋯n21) 其理论解为…...
【深度学习环境】Docker
1. Docker 相关安装配置 1.1 docker 安装 参考:https://www.runoob.com/docker/ubuntu-docker-install.html 1.2 nvidia-docker 安装 参考:https://zhuanlan.zhihu.com/p/37519492 1.3 代理加速 参考:https://yeasy.gitbook.io/docker_…...
基于vscode开发vue项目的详细步骤教程 2 第三方图标库FontAwesome
1、Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 2、Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目_水w的博客-CSDN博客 3、基于vscode开发vue项目的详细步骤教程_水w的博客-CSDN博客 目录 六、第三方图标库FontAwesome 1 安装FontAwesome 解决报…...
今天面了个腾讯拿25K出来的软件测试工程师,让我见识到了真正的天花板...
今天上班开早会就是新人见面仪式,听说来了个很厉害的大佬,年纪还不大,是上家公司离职过来的,薪资已经达到中高等水平,很多人都好奇不已,能拿到这个薪资应该人不简单,果然,自我介绍的…...
OSG三维渲染引擎编程学习之六十九:“第六章:OSG场景工作机制” 之 “6.9 OSG数据变量”
目录 第六章 OSG场景工作机制 6.9 OSG数据变量 第六章 OSG场景工作机制 作为一个成熟的三维渲染引擎,需要提供快速获取场景数据、节点等信息,具备自定义数据或动画更新接口,能接收应用程序或窗口等各类消息。OSG三维渲染引擎能较好地完成上述工作,OSG是采用什么方式或工作…...
Tektronix泰克TDP3500差分探头3.5GHz
附加功能: 带宽:3.5 GHz 差分输入电容:≤0.3 pF 差分输入电阻:100 kΩ DC pk 交流输入电压:15 V >60 dB 在 1 MHz 和 >25 dB 在 1 GHz CMRR 出色的共模抑制——减少较高共模环境中的测量误差 低电容和电阻负载…...
轻松实现内网穿透:实现远程访问你的私人网络
导语:内网穿透是什么?为什么我们需要它?今天我们将介绍这个令人惊叹的技术,让你实现远程访问你的私人网络。 使用内网穿透,轻松实现外网访问本地部署的网站 第一部分:什么是内网穿透? 通俗解释…...
广州免费推广网站建设/温岭网络推广
如今,最流行的云计算模式就是基础设施即服务(IaaS),但是它并不总是云应用安全的最佳模式。很多用户都知道平台即服务(PaaS)和软件即服务(SaaS)可以实现较好的成本节约,尤其对于那些无法访问高技能云计算技术资源的用户来说,更是如…...
三亚市政府网站的建设/网站流量排行
由Semtech、Cisco、IBM、ST、法国电信Orange、阿里巴巴等等会员组合成的LoRa 协会所制定出的标准通讯协议 LoRaWAN已经成为市场所通用的协议。其包含了需多的通讯沟通模式如适合省电节点的的固定双向通讯Class A、和提供需要实时双向沟通用的最大接收时间窗口 Class C 及介于中…...
职业病院网站建设/网站推广优化之八大方法
对象或类内部往往会包含别的对象,在创建成员对象时你可能习惯于使用使用传统的new来创建对象。但是这种方式会造成两个对象之间的依赖。 工厂模式就是一种有助于消除或减弱这种依赖的设计模式。 书中用自行车商店的例子阐述了简单工厂模式。先是用传统的方式&#x…...
新手做视频网站好/百度官网首页登录
只用于发post请求 #pragma mark - post请求 - (void)post {// 1.创建请求对象NSURL *url [NSURL URLWithString:"http://192.168.1.200:8080/Server/login"];ASIFormDataRequest *request [ASIFormDataRequest requestWithURL:url];// 2.添加请求参数(请求体中的参…...
网站是公司域名是个人可以吗/网络营销方案的制定
以下是按照面积对形状进行排序的代码,仅供参考。 Sub 按面积排序曲线物件() For diaogangxiongActivePage.Shapes.All.CreateSelection’全选Dim OrigSelection As ShapeRangeSet OrigSelection = ActiveSelectionRangeOrigSelection.ConvertToCurves’转曲线Dim grp1 As Sha…...
wordpress淘宝客模板修改教程/谷歌广告优化
SQL分类 DDL(Data Definition Languages) 数据定义语言,这些语句定义了不同的数据字段、数据库、表、列、索引等数据。 常用的语句关键字主要包括 create(添加),drop(删除),alter(修…...