Functional Options
問題點(diǎn)
當(dāng)一個(gè)函數(shù)有很多參數(shù),為了方便函數(shù)的使用,我們會給一些參數(shù)設(shè)定默認(rèn)值,調(diào)用時(shí)只需要傳與默認(rèn)值不同的參數(shù)即可
問題分析
需求:
上傳文件到金山云的 KS3, 上傳的時(shí)候有很多選擇, 如: 文件的 ACL 權(quán)限是否公開, 文件的存儲類型是否為低頻存儲或正常存儲, 文件的格式是普通文本還是二進(jìn)制文件等等.
實(shí)現(xiàn)
方法1:? 每一個(gè)選項(xiàng)均作為參數(shù)
| // 配置對象 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)),??????// 默認(rèn)權(quán)限為 ACLPrivate ??????Body:???????? reader,???????????????????????????// 要上傳的內(nèi)容 ??????ContentType:? aws.String(string(mimeType)),?????// 金山云默認(rèn)為 application/octet-stream ??????StorageClass: aws.String(string(storageClass)),?// 金山云默認(rèn)為 標(biāo)準(zhǔn)存儲類型, 請注意設(shè)置 ???} ???_, err := client.ks3.PutObject(params) ???return?err } |
優(yōu)點(diǎn):
簡單明了, 非常易于理解
缺點(diǎn):
不方便擴(kuò)展, 新增需求原先代碼編譯錯(cuò)誤
參數(shù)可能無窮擴(kuò)展, 調(diào)用方代碼非常長
無法使用默認(rèn)值
方法2:? 創(chuàng)建配置對象
| // 配置對象 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)),??????// 金山云默認(rèn)為 Private ??????Body:???????? reader,??????????????????????????????????// 要上傳的內(nèi)容 ??????ContentType:? aws.String(string(option.mimeType)),?????// 金山云默認(rèn)為 application/octet-stream ??????StorageClass: aws.String(string(option.storageClass)),?// 金山云默認(rèn)為 標(biāo)準(zhǔn)存儲類型, 請注意設(shè)置 ???} ???_, err := client.ks3.PutObject(params) ???return?err } |
優(yōu)點(diǎn):
實(shí)現(xiàn)簡單, 易于理解, 新增選項(xiàng)相對容易
缺點(diǎn):
必須傳 option 這個(gè)參數(shù),? 即使想使用金山云的默認(rèn)值
強(qiáng)制方法調(diào)用者需要額外創(chuàng)建 option 的對象, 接口不友好
無法使用默認(rèn)值
方法3 : 配置項(xiàng)作為指針
| // 配置對象 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)),??????// 默認(rèn)權(quán)限為 ACLPrivate ??????Body:???????? reader,???????????????????????????????????// 要上傳的內(nèi)容 ??????ContentType:? aws.String(string(options.mimeType)),?????// 金山云默認(rèn)為 application/octet-stream ??????StorageClass: aws.String(string(options.storageClass)),?// 金山云默認(rèn)為 標(biāo)準(zhǔn)存儲類型, 請注意設(shè)置 ???} ???_, err := client.ks3.PutObject(params) ???return?err } |
優(yōu)點(diǎn):
可以直接傳一個(gè) nil 進(jìn)去
缺點(diǎn):?
api 很奇怪, 傳一個(gè) nil
無法使用默認(rèn)值
方法4:?選項(xiàng)模式
| // Option 額外操作 type Option func(*options) type options struct { ???// Set ???aclType????? ACLType ???mimeType???? MIMEType ???storageClass StorageClass ???// Get ???header Header } // WithACLType 設(shè)置資源的訪問權(quán)限 func WithACLType(aclType ACLType) Option { ???return?func(o *options) { ??????o.aclType = aclType ???} } // WithMIMEType 設(shè)置資源的存儲格式(如文本, JSON, 圖片, 視頻) func WithMIMEType(mimeType MIMEType) Option { ???return?func(o *options) { ??????o.mimeType = mimeType ???} } // WithStorageClass 設(shè)置資源的存取類型(如標(biāo)準(zhǔn)存儲類型,低頻訪問存儲類型,歸檔存儲類型) 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)),??????// 默認(rèn)權(quán)限為 ACLPrivate ??????Body:???????? reader,??????????????????????????????????????????// 要上傳的內(nèi)容 ??????ContentType:? aws.String(string(client.options.mimeType)),?????// 金山云默認(rèn)為 application/octet-stream ??????StorageClass: aws.String(string(client.options.storageClass)),?// 金山云默認(rèn)為 標(biāo)準(zhǔn)存儲類型, 請注意設(shè)置 ???} ???_, err := client.ks3.PutObject(params) ???return?err } |
優(yōu)點(diǎn):?
可以使用默認(rèn)值, 只需要傳非默認(rèn)值以外的值
可以校驗(yàn)傳入的值
缺點(diǎn):
實(shí)現(xiàn)較復(fù)雜, 使用閉包
?
轉(zhuǎn)載于:https://www.cnblogs.com/Zereker/p/11396647.html
總結(jié)
以上是生活随笔為你收集整理的Functional Options的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ticker 未释放导致的 CPU 占用
- 下一篇: 使用expvar进行监控