golang 設計模式之選項模式

2021-08-16 17:45:50 字數 2251 閱讀 3707

有時候乙個函式會有很多引數,為了方便函式的使用,我們會給希望給一些引數設定預設值,呼叫時只需要傳與預設值不同的引數即可,類似於 python 裡面的預設引數和字典引數,雖然 golang 裡面既沒有預設引數也沒有字典引數,但是我們有選項模式

在這之前,首先需要介紹一下可變長引數列表,顧名思義,就是引數的個數不固定,可以是乙個也可以是多個,最典型的用法就是標準庫裡面的fmt.printf,語法比較簡單,如下面例子實現任意多個引數的加法

func add(nums ...int) int 

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) 

// 呼叫方法

myfunc1("requiredstr", "defaultstr1", "defaultstr2",1,2)

這種實現比較簡單,但是同時傳入引數較多,對呼叫方來說,使用的成本就會比較高,而且每個引數的具體含義這裡並不清晰,很容易出錯

那選項模式怎麼實現這個需求呢?先來看下最終的效果

myfunc2("requiredstr")

myfunc2("requiredstr", withoptionstr1("mystr1"))

myfunc2("requiredstr", withoptionstr2andint2("mystr2",22), withoptionint1(11))

如上面**所示,你可以根據自己的需求選擇你需要傳入的引數,大大簡化了函式呼叫的複雜度,並且每個引數都有了清晰明確的含義

那怎麼實現上面的功能呢

定義可選項和預設值

首先定義可選項和預設值,這裡有4個可選項,第乙個引數為必填項

type myfuncoptions struct 

var defaultmyfuncoptions = myfuncoptions

實現 with 方法

這些 with 方法看起來有些古怪,接受乙個選項引數,返回乙個選項方法,而選項方法以選項作為引數負責修改選項的值,如果沒看明白沒關係,可以先看函式功能如何實現

type myfuncoption func(options *myfuncoptions)

func withoptionstr1(str1 string) myfuncoption

}func withoptionint1(int1 int) myfuncoption

}func withoptionstr2andint2(str2 string, int2 int) myfuncoption

}

這裡我們讓 optionstr2 和 optionint2 合併一起設定,實際應用場景中可以用這種方式將相關的引數放到一起設定

實現函式功能

func myfunc2(requiredstr string, opts ...myfuncoption) 

fmt.println(requiredstr, options.optionstr1, options.optionstr2, options.optionint1, options.optionint2)

}

使用 with 方法返回的選項方法作為引數列表,用這些方法去設定選項

從這裡可以看到,為了實現選項的功能,我們增加了很多的**,實現成本相對還是較高的,所以實踐中需要根據自己的業務場景去權衡是否需要使用。個人總結滿足下面條件可以考慮使用選項模式

引數確實比較複雜,影響呼叫方使用

引數確實有比較清晰明確的預設值

為引數的後續拓展考慮

在 golang 的很多開源專案裡面也用到了選項模式,比如 grpc 中的 rpc 方法就是採用選項模式設計的,除了必填的 rpc 引數外,還可以一些選項引數,grpc_retry 就是通過這個機制實現的,可以實現自動重試功能

Golang 選項模式(Option模式)

option模式的專業術語為 functional options pattern 函式式選項模式 option模式為golang的開發者提供了將乙個函式的引數設定為可選的功能,也就是說我們可以選擇引數中的某幾個,並且可以按任意順序傳入引數。比如針對特殊場景需要不同引數的情況,c 可以直接用過載來寫...

golang設計模式之建造者模式

最近一直在寫框架,這個系列也好久沒更新了,抽時間更新一篇 wiki 建造者模式 builder pattern 將乙個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。直白一點的說,就是將我們在開發過程中遇到的大型物件,拆分成多個小物件,然後將多個小物件組裝成大物件,並且對外部隱藏...

golang設計模式之單例模式

保證乙個類只有乙個例項,並且提供乙個訪問該例項的全域性訪問點 由於單例模式只生成乙個例項,減少系統效能開銷,當乙個物件的生產需要比較多資源時,就可以通過在應用啟動的時候直接產生乙個單例物件,然後永久駐留記憶體,例如日誌模組 單例模式可以在系統設定全域性訪問點,優化資源共享問題,比如資料庫裡連線池 餓...