golang 設計模式之選項模式
有時候一個函式會有很多引數,為了方便函式的使用,我們會給希望給一些引數設定預設值,呼叫時只需要傳與預設值不同的引數即可,類似於 python 裡面的預設引數和字典引數,雖然 golang 裡面既沒有預設引數也沒有字典引數,但是我們有選項模式
可變長引數列表
在這之前,首先需要介紹一下可變長引數列表,顧名思義,就是引數的個數不固定,可以是一個也可以是多個,最典型的用法就是標準庫裡面的 fmt.Printf
,語法比較簡單,如下面例子實現任意多個引數的加法
func add(nums ...int) int {
sum := 0
for _, num := range nums {
sum += num
}
return sum
}
So(add(1, 2), ShouldEqual, 3)
So(add(1, 2, 3), ShouldEqual, 6)
在型別前面加 ...
來表示這個型別的變長引數列表,使用上把引數當成 slice
來用即可
選項模式
假設我們要實現這樣一個函式,這個函式接受 5 個引數,三個 string
(其中第一個引數是必填引數),兩個 int
,這裡功能只是簡單輸出這個引數,於是我們可以簡單用如下程式碼實現
func MyFunc1(requiredStr string, str1 string, str2 string, int1 int, int2 int) {
fmt.Println(requiredStr, str1, str2, int1, int2)
}
// 呼叫方法
MyFunc1("requiredStr", "defaultStr1", "defaultStr2", 1, 2)
這種實現比較簡單,但是同時傳入引數較多,對呼叫方來說,使用的成本就會比較高,而且每個引數的具體含義這裡並不清晰,很容易出錯
那選項模式怎麼實現這個需求呢?先來看下最終的效果
MyFunc2("requiredStr")
MyFunc2("requiredStr", WithOptionStr1("mystr1"))
MyFunc2("requiredStr", WithOptionStr2AndInt2("mystr2", 22), WithOptionInt1(11))
如上面程式碼所示,你可以根據自己的需求選擇你需要傳入的引數,大大簡化了函式呼叫的複雜度,並且每個引數都有了清晰明確的含義
那怎麼實現上面的功能呢
定義可選項和預設值
首先定義可選項和預設值,這裡有 4 個可選項,第一個引數為必填項
type MyFuncOptions struct {
optionStr1 string
optionStr2 string
optionInt1 int
optionInt2 int
}
var defaultMyFuncOptions = MyFuncOptions{
optionStr1: "defaultStr1",
optionStr2: "defaultStr2",
optionInt1: 1,
optionInt2: 2,
}
實現 With 方法
這些 With 方法看起來有些古怪,接受一個選項引數,返回一個選項方法,而選項方法以選項作為引數負責修改選項的值,如果沒看明白沒關係,可以先看函式功能如何實現
type MyFuncOption func(options *MyFuncOptions)
func WithOptionStr1(str1 string) MyFuncOption {
return func(options *MyFuncOptions) {
options.optionStr1 = str1
}
}
func WithOptionInt1(int1 int) MyFuncOption {
return func(options *MyFuncOptions) {
options.optionInt1 = int1
}
}
func WithOptionStr2AndInt2(str2 string, int2 int) MyFuncOption {
return func(options *MyFuncOptions) {
options.optionStr2 = str2
options.optionInt2 = int2
}
}
這裡我們讓 optionStr2 和 optionInt2 合併一起設定,實際應用場景中可以用這種方式將相關的引數放到一起設定
實現函式功能
func MyFunc2(requiredStr string, opts ...MyFuncOption) {
options := defaultMyFuncOptions
for _, o := range opts {
o(&options)
}
fmt.Println(requiredStr, options.optionStr1, options.optionStr2, options.optionInt1, options.optionInt2)
}
使用 With 方法返回的選項方法作為引數列表,用這些方法去設定選項
選項模式的應用
從這裡可以看到,為了實現選項的功能,我們增加了很多的程式碼,實現成本相對還是較高的,所以實踐中需要根據自己的業務場景去權衡是否需要使用。個人總結滿足下面條件可以考慮使用選項模式
- 引數確實比較複雜,影響呼叫方使用
- 引數確實有比較清晰明確的預設值
- 為引數的後續擴充考慮
在 golang 的很多開源專案裡面也用到了選項模式,比如 grpc 中的 rpc 方法就是採用選項模式設計的,除了必填的 rpc 引數外,還可以一些選項引數,grpc_retry 就是通過這個機制實現的,可以實現自動重試功能
參考連結
- Go 函式式選項模式:<https://studygolang.com/articles/12329>
- Functional Options Pattern in Go:<https://halls-of-valhalla.org/beta/articles/functional-options-pattern-in-go,54/>
> 轉載請註明出處 > 本文連結:<http://hatlonely.github.io/2018/03/10/golang-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E9%80%89%E9%A1%B9%E6%A8%A1%E5%BC%8F/>
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- Golang 常見設計模式之選項模式Golang設計模式
- golang設計模式之單例模式Golang設計模式單例
- golang設計模式之迭代器模式Golang設計模式
- golang設計模式之建造者模式Golang設計模式
- golang設計模式之原型模式Golang設計模式原型
- golang設計模式之工廠方法模式Golang設計模式
- golang設計模式之觀察者模式Golang設計模式
- golang設計模式之抽象工廠模式Golang設計模式抽象
- golang中的選項模式Golang模式
- golang設計模式之簡單工廠模式Golang設計模式
- Golang 常見設計模式之裝飾模式Golang設計模式
- Golang 常見設計模式之單例模式Golang設計模式單例
- GoLang設計模式08 - 命令模式Golang設計模式
- GoLang設計模式15 - 策略模式Golang設計模式
- GoLang設計模式20 - 組合模式Golang設計模式
- GoLang設計模式17 - 訪客模式Golang設計模式
- GoLang設計模式19 - 橋接模式Golang設計模式橋接
- GoLang設計模式01 - 建造者模式Golang設計模式
- GoLang設計模式02 - 工廠模式Golang設計模式
- GoLang設計模式04 - 單例模式Golang設計模式單例
- GoLang設計模式05 - 原型模式Golang設計模式原型
- GoLang設計模式06 - 物件池模式Golang設計模式物件
- GoLang設計模式14 - 狀態模式Golang設計模式
- GoLang設計模式12 - 空物件模式Golang設計模式物件
- GoLang設計模式21 - 裝飾模式Golang設計模式
- GoLang設計模式11 - 備忘錄模式Golang設計模式
- GoLang設計模式13 - 觀察者模式Golang設計模式
- 設計模式之策略模式設計模式
- 設計模式之代理模式設計模式
- 設計模式之Plugin模式設計模式Plugin
- 《設計模式》之代理模式設計模式
- 設計模式之命令模式設計模式
- 設計模式之-命令模式設計模式
- 設計模式之【策略模式】設計模式
- 設計模式之單例設計模式設計模式單例
- 一.設計模式之工廠設計模式設計模式
- JavaScript設計模式之建立型設計模式JavaScript設計模式
- Javascript設計模式之代理模式JavaScript設計模式