问题点

当一个函数有很多参数,为了方便函数的使用,我们会给一些参数设定默认值,调用时只需要传与默认值不同的参数即可

问题分析

需求:

上传文件到金山云的 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相关推荐

  1. Functional Options: Go中实现优雅的API的方法 | Gopher Daily (2021.10.22)

    每日一谚:学会不要马上增加太多的功能,要把核心思想建立起来并进行测试 - Leah Culver Go技术生态 Go很大可能在go 1.19版本中支持编译器的FGO(feedback-guided o ...

  2. Functional Options Patter--golang 函数参数选项配置

    原文地址:https://blog.keyboardman.me/2018/01/03/grpc-functional-options-patter/

  3. Golang之函数选项模式

    仅做记录 /*Functional Options函数选项模式(简称FOP模式)既保持了兼容性,而且每增加1个新属性只需要1个With函数即可,大大减少了修改代码的风险 */ package main ...

  4. 曹大带我学 Go(7)—— 如何优雅地指定配置项

    你好,我是小X. 曹大最近开 Go 课程了,小X 正在和曹大学 Go. 这个系列会讲一些从课程中学到的让人醍醐灌顶的东西,拨云见日,带你重新认识 Go. 最近一个年久失修的库导致了线上事故,不得不去做 ...

  5. Kratos技术系列|从Kratos设计看Go微服务工程实践

    导读 github.com/go-kratos/kratos(以下简称Kratos)是一套轻量级 Go 微服务框架,致力于提供完整的微服务研发体验,整合相关框架及周边工具后,微服务治理相关部分可对整体 ...

  6. 语言与golang语言运行速度_Golang语言情怀第13期 Go 语言设计模式 介绍

    设计模式是什么 俗话说:站在别人的肩膀上,我们会看得更远.设计模式的出现可以让我们站在前人的肩膀上,通过一些成熟的设计方案来指导新项目的开发和设计,以便于我们开发出具有更好的灵活性和可扩展性,也更易于 ...

  7. golang 切片 接口_Go编程模式:切片,接口,时间和性能

    在本篇文章中,我会对 Go 语言编程模式的一些基本技术和要点,这样可以让你更容易掌握 Go 语言编程.其中,主要包括,数组切片的一些小坑,还有接口编程,以及时间和程序运行性能相关的话题. 本文是全系列 ...

  8. Practical Go: Real world advice for writing maintainable Go programs

    转载地址:Practical Go: Real world advice for writing maintainable Go programs Table of Contents Introduc ...

  9. Uber Go语言编码规范

    Uber是世界领先的生活出行服务提供商,也是Go语言的早期adopter,根据Uber工程博客的内容,大致可以判断出Go语言在Uber内部扮演了十分重要的角色.Uber内部的Go语言工程实践也是硕果累 ...

最新文章

  1. go语言搭建代理服务器_Go实现Https代理服务
  2. Singleton模式
  3. Java 设计模式之《观察者模式》
  4. 从Eclipse转移到IntelliJ IDEA一点心得
  5. Windows Mobile 技术开发黄金周系列课程
  6. 比較++和+的运算符优先级
  7. python数组随机打乱_对Python random模块打乱数组顺序的实例讲解
  8. 铃铛计数问题 解题报告
  9. vb6 判断打印机是否有效_讲述3D打印机怎么用 初学者必看
  10. JavaScript常用设计模式
  11. 您从事运维有几年了?
  12. 数据库中常用使用场景
  13. 话费充值 php,话费充值示例代码
  14. python多线程破解压缩包_python利用itertools生成密码字典并多线程撞库破解rar密码...
  15. java groovy_java 和groovy的混合使用
  16. 有道手机词典(安卓版)离线和发音包…
  17. Frp内网穿透保姆级教程 windows内网穿透
  18. ROUGE和pyrouge的安装
  19. 小米平板1 android5,小米平板5即将到来?对小米平板前几代做了一下总结
  20. 获取网络连接名称“本地连接”的两种方法

热门文章

  1. 解决vs启动出现“cannot find one or more components .Please reinstall the application”
  2. Python3 高级特性
  3. 深度优先搜索 和问题 简单函数递归 “加 还是不加”
  4. requirejs 加载其它js
  5. TCP,IP,HTTP,SOCKET区别和联系
  6. bzoj 1004: [HNOI2008]Cards
  7. 剑指offer六十一之序列化二叉树(待补充)
  8. 理解RESTful架构【转】
  9. java 11-7String类里的方法的一些案例
  10. artdialog 异步加载页面 生成验证码