golang 設計模式之選項模式

有時候一個函數會有不少參數,爲了方便函數的使用,咱們會給但願給一些參數設定默認值,調用時只須要傳與默認值不一樣的參數便可,相似於 python 裏面的默認參數和字典參數,雖然 golang 裏面既沒有默認參數也沒有字典參數,可是咱們有選項模式python

可變長參數列表

在這以前,首先須要介紹一下可變長參數列表,顧名思義,就是參數的個數不固定,能夠是一個也能夠是多個,最典型的用法就是標準庫裏面的 fmt.Printf,語法比較簡單,以下面例子實現任意多個參數的加法git

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 來用便可github

選項模式

假設咱們要實現這樣一個函數,這個函數接受5個參數,三個 string(其中第一個參數是必填參數),兩個 int,這裏功能只是簡單輸出這個參數,因而咱們能夠簡單用以下代碼實現golang

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)

這種實現比較簡單,可是同時傳入參數較多,對調用方來講,使用的成本就會比較高,並且每一個參數的具體含義這裏並不清晰,很容易出錯函數

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

MyFunc2("requiredStr")
MyFunc2("requiredStr", WithOptionStr1("mystr1"))
MyFunc2("requiredStr", WithOptionStr2AndInt2("mystr2", 22), WithOptionInt1(11))

如上面代碼所示,你能夠根據本身的需求選擇你須要傳入的參數,大大簡化了函數調用的複雜度,而且每一個參數都有了清晰明確的含義設計

那怎麼實現上面的功能呢code

定義可選項和默認值

首先定義可選項和默認值,這裏有4個可選項,第一個參數爲必填項rpc

type MyFuncOptions struct {
    optionStr1 string
    optionStr2 string
    optionInt1 int
    optionInt2 int
}

var defaultMyFuncOptions = MyFuncOptions{
    optionStr1: "defaultStr1",
    optionStr2: "defaultStr2",
    optionInt1: 1,
    optionInt2: 2,
}

實現 With 方法

這些 With 方法看起來有些古怪,接受一個選項參數,返回一個選項方法,而選項方法以選項做爲參數負責修改選項的值,若是沒看明白不要緊,能夠先看函數功能如何實現get

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 方法返回的選項方法做爲參數列表,用這些方法去設置選項

選項模式的應用

從這裏能夠看到,爲了實現選項的功能,咱們增長了不少的代碼,實現成本相對仍是較高的,因此實踐中須要根據本身的業務場景去權衡是否須要使用。我的總結知足下面條件能夠考慮使用選項模式

  1. 參數確實比較複雜,影響調用方使用
  2. 參數確實有比較清晰明確的默認值
  3. 爲參數的後續拓展考慮

在 golang 的不少開源項目裏面也用到了選項模式,好比 grpc 中的 rpc 方法就是採用選項模式設計的,除了必填的 rpc 參數外,還能夠一些選項參數,grpc_retry 就是經過這個機制實現的,能夠實現自動重試功能

參考連接

轉載請註明出處
本文連接: http://hatlonely.github.io/20...
相關文章
相關標籤/搜索