Functional Options
问题点
当一个函数有很多参数,为了方便函数的使用,我们会给一些参数设定默认值,调用时只需要传与默认值不同的参数即可
问题分析
需求:
上传文件到金山云的 KS3, 上传的时候有很多选择, 如: 文件的 ACL 权限是否公开, 文件的存储类型是否为低频存储或正常存储, 文件的格式是普通文本还是二进制文件等等.
实现
方法1: 每一个选项均作为参数
// 配置对象
type options struct {
// Set
aclType ACLType
mimeType MIMEType
storageClass StorageClass
// Get
header Header
}
// 上传文件
func (client *ks3Client) PutObject(objectKey string, reader io.ReadSeeker, aclType ACLType, mimeType MIMEType, storageClass StorageClass) error {
params := &s3.PutObjectInput{
Bucket: aws.String(client.bucket), // bucket名称
Key: aws.String(objectKey), // object key
ACL: aws.String(string(aclType)), // 默认权限为 ACLPrivate
Body: reader, // 要上传的内容
ContentType: aws.String(string(mimeType)), // 金山云默认为 application/octet-stream
StorageClass: aws.String(string(storageClass)), // 金山云默认为 标准存储类型, 请注意设置
}
_, err := client.ks3.PutObject(params)
return err
}
|
优点:
简单明了, 非常易于理解
缺点:
不方便扩展, 新增需求原先代码编译错误
参数可能无穷扩展, 调用方代码非常长
无法使用默认值
方法2: 创建配置对象
// 配置对象
type Option struct {
// Set
aclType ACLType
mimeType MIMEType
storageClass StorageClass
// Get
header Header
}
func (client *ks3Client) PutObject(objectKey string, reader io.ReadSeeker, option Option) error {
params := &s3.PutObjectInput{
Bucket: aws.String(client.bucket), // bucket名称
Key: aws.String(objectKey), // object key
ACL: aws.String(string(option.aclType)), // 金山云默认为 Private
Body: reader, // 要上传的内容
ContentType: aws.String(string(option.mimeType)), // 金山云默认为 application/octet-stream
StorageClass: aws.String(string(option.storageClass)), // 金山云默认为 标准存储类型, 请注意设置
}
_, err := client.ks3.PutObject(params)
return err
}
|
优点:
实现简单, 易于理解, 新增选项相对容易
缺点:
必须传 option 这个参数, 即使想使用金山云的默认值
强制方法调用者需要额外创建 option 的对象, 接口不友好
无法使用默认值
方法3 : 配置项作为指针
// 配置对象
type options struct {
// Set
aclType ACLType
mimeType MIMEType
storageClass StorageClass
// Get
header Header
}
// 上传文件
func (client *ks3Client) PutObject(objectKey string, reader io.ReadSeeker, options *options) error {
params := &s3.PutObjectInput{
Bucket: aws.String(client.bucket), // bucket名称
Key: aws.String(objectKey), // object key
ACL: aws.String(string(options.aclType)), // 默认权限为 ACLPrivate
Body: reader, // 要上传的内容
ContentType: aws.String(string(options.mimeType)), // 金山云默认为 application/octet-stream
StorageClass: aws.String(string(options.storageClass)), // 金山云默认为 标准存储类型, 请注意设置
}
_, err := client.ks3.PutObject(params)
return err
}
|
优点:
可以直接传一个 nil 进去
缺点:
api 很奇怪, 传一个 nil
无法使用默认值
方法4: 选项模式
// Option 额外操作
type Option func(*options)
type options struct {
// Set
aclType ACLType
mimeType MIMEType
storageClass StorageClass
// Get
header Header
}
// WithACLType 设置资源的访问权限
func WithACLType(aclType ACLType) Option {
return func(o *options) {
o.aclType = aclType
}
}
// WithMIMEType 设置资源的存储格式(如文本, JSON, 图片, 视频)
func WithMIMEType(mimeType MIMEType) Option {
return func(o *options) {
o.mimeType = mimeType
}
}
// WithStorageClass 设置资源的存取类型(如标准存储类型,低频访问存储类型,归档存储类型)
func WithStorageClass(storageClass StorageClass) Option {
return func(o *options) {
o.storageClass = storageClass
}
}
// GetHeaderMeta 获取资源的头信息, 包括 Content-Type, ContentLength
func GetHeaderMeta(header Header) Option {
return func(o *options) {
o.header = header
}
}
func (client *ks3Client) PutObject(objectKey string, reader io.ReadSeeker, option ...Option) error {
client.options = defaultPutOption
for _, opt := range option {
opt(&client.options)
}
params := &s3.PutObjectInput{
Bucket: aws.String(client.bucket), // bucket名称
Key: aws.String(objectKey), // object key
ACL: aws.String(string(client.options.aclType)), // 默认权限为 ACLPrivate
Body: reader, // 要上传的内容
ContentType: aws.String(string(client.options.mimeType)), // 金山云默认为 application/octet-stream
StorageClass: aws.String(string(client.options.storageClass)), // 金山云默认为 标准存储类型, 请注意设置
}
_, err := client.ks3.PutObject(params)
return err
}
|
优点:
可以使用默认值, 只需要传非默认值以外的值
可以校验传入的值
缺点:
实现较复杂, 使用闭包
转载于:https://www.cnblogs.com/Zereker/p/11396647.html
Functional Options相关推荐
- Functional Options: Go中实现优雅的API的方法 | Gopher Daily (2021.10.22)
每日一谚:学会不要马上增加太多的功能,要把核心思想建立起来并进行测试 - Leah Culver Go技术生态 Go很大可能在go 1.19版本中支持编译器的FGO(feedback-guided o ...
- Functional Options Patter--golang 函数参数选项配置
原文地址:https://blog.keyboardman.me/2018/01/03/grpc-functional-options-patter/
- Golang之函数选项模式
仅做记录 /*Functional Options函数选项模式(简称FOP模式)既保持了兼容性,而且每增加1个新属性只需要1个With函数即可,大大减少了修改代码的风险 */ package main ...
- 曹大带我学 Go(7)—— 如何优雅地指定配置项
你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近一个年久失修的库导致了线上事故,不得不去做 ...
- Kratos技术系列|从Kratos设计看Go微服务工程实践
导读 github.com/go-kratos/kratos(以下简称Kratos)是一套轻量级 Go 微服务框架,致力于提供完整的微服务研发体验,整合相关框架及周边工具后,微服务治理相关部分可对整体 ...
- 语言与golang语言运行速度_Golang语言情怀第13期 Go 语言设计模式 介绍
设计模式是什么 俗话说:站在别人的肩膀上,我们会看得更远.设计模式的出现可以让我们站在前人的肩膀上,通过一些成熟的设计方案来指导新项目的开发和设计,以便于我们开发出具有更好的灵活性和可扩展性,也更易于 ...
- golang 切片 接口_Go编程模式:切片,接口,时间和性能
在本篇文章中,我会对 Go 语言编程模式的一些基本技术和要点,这样可以让你更容易掌握 Go 语言编程.其中,主要包括,数组切片的一些小坑,还有接口编程,以及时间和程序运行性能相关的话题. 本文是全系列 ...
- Practical Go: Real world advice for writing maintainable Go programs
转载地址:Practical Go: Real world advice for writing maintainable Go programs Table of Contents Introduc ...
- Uber Go语言编码规范
Uber是世界领先的生活出行服务提供商,也是Go语言的早期adopter,根据Uber工程博客的内容,大致可以判断出Go语言在Uber内部扮演了十分重要的角色.Uber内部的Go语言工程实践也是硕果累 ...
最新文章
- go语言搭建代理服务器_Go实现Https代理服务
- Singleton模式
- Java 设计模式之《观察者模式》
- 从Eclipse转移到IntelliJ IDEA一点心得
- Windows Mobile 技术开发黄金周系列课程
- 比較++和+的运算符优先级
- python数组随机打乱_对Python random模块打乱数组顺序的实例讲解
- 铃铛计数问题 解题报告
- vb6 判断打印机是否有效_讲述3D打印机怎么用 初学者必看
- JavaScript常用设计模式
- 您从事运维有几年了?
- 数据库中常用使用场景
- 话费充值 php,话费充值示例代码
- python多线程破解压缩包_python利用itertools生成密码字典并多线程撞库破解rar密码...
- java groovy_java 和groovy的混合使用
- 有道手机词典(安卓版)离线和发音包…
- Frp内网穿透保姆级教程 windows内网穿透
- ROUGE和pyrouge的安装
- 小米平板1 android5,小米平板5即将到来?对小米平板前几代做了一下总结
- 获取网络连接名称“本地连接”的两种方法
热门文章
- 解决vs启动出现“cannot find one or more components .Please reinstall the application”
- Python3 高级特性
- 深度优先搜索 和问题 简单函数递归 “加 还是不加”
- requirejs 加载其它js
- TCP,IP,HTTP,SOCKET区别和联系
- bzoj 1004: [HNOI2008]Cards
- 剑指offer六十一之序列化二叉树(待补充)
- 理解RESTful架构【转】
- java 11-7String类里的方法的一些案例
- artdialog 异步加载页面 生成验证码