Go 編寫優雅的構造函數。
假設有一個名為 ViewManager
的結構體如下:
1 type ViewManager struct {
2 fs http.FileSystem // 文件系統
3 suffix string // 視圖文件的後綴
4 cache bool // 是否開啟緩存
5}
6
7func New(fs http.FileSystem) *ViewManager {
8 return &ViewManager{
9 fs: fs,
10 cache: true,
11 suffix: ".tmpl",
12 }
13}
其所有成員都是不可寫的,在我們需要創建不同 suffix、cache 的實例時,我們可以輕易地通過新增構造函數來實現,如 NewSuffix(fs http.FileSystem, suffix string)
、NewCache(fs http.FileSystem, cache bool)
,但是這樣看起來繁瑣不美觀。其實我們可以通過一個構造函數來實現。
配置結構
第一種很簡單,定義一個配置結構,然後傳入到構造函數即可。
1type Config struct {
2 Suffix string
3 Cache bool
4}
5
6func New(fs http.FileSystem, cfg Config) *ViewManager {
7 m := &ViewManager{
8 fs: fs,
9 cache: cfg.Cache,
10 suffix: ".tmpl",
11 }
12
13 if cfg.Suffix != "" {
14 m.suffix = suffix
15 }
16
17 return m
18}
配置函數
配置函數和配置結構類似,只是利用函數的方式進行設置:
1type Option func(*ViewManager)
2
3func Suffix(v string) Option {
4 return func(m *ViewManager) {
5 m.suffix = v
6 }
7}
8
9func Cache(v bool) Option {
10 return func(m *ViewManager) {
11 m.cache = v
12 }
13}
14
15func New(fs http.FileSystem, opts ... Option) *ViewManager {
16 m := &ViewManager{
17 fs: fs,
18 cache: true,
19 suffix: ".tmpl",
20 }
21
22 for _, f := range opts {
23 f(m)
24 }
25
26 return m
27}
區別
兩種方式很常見,在標準庫和第三方庫都可以看到,不過筆者更喜歡後者,無需在構造函數進行過多的判斷,編寫單元測試也更容易。