選項模式

更新、更全的《Go從入門到放棄》的更新網站,更有python、go、人工智能教學等着你:http://www.javashuo.com/article/p-mxrjjcnn-hn.htmlpython

本文主要介紹了Go語言中函數式選項模式及該設計模式在實際編程中的應用。git

1、爲何須要函數式選項模式?

最近看go-micro/options.go源碼的時候,發現了一段關於服務註冊的代碼以下:github

type Options struct {
    Broker    broker.Broker
    Cmd       cmd.Cmd
    Client    client.Client
    Server    server.Server
    Registry  registry.Registry
    Transport transport.Transport

    // Before and After funcs
    BeforeStart []func() error
    BeforeStop  []func() error
    AfterStart  []func() error
    AfterStop   []func() error

    // Other options for implementations of the interface
    // can be stored in a context
    Context context.Context
}

func newOptions(opts ...Option) Options {
    opt := Options{
        Broker:    broker.DefaultBroker,
        Cmd:       cmd.DefaultCmd,
        Client:    client.DefaultClient,
        Server:    server.DefaultServer,
        Registry:  registry.DefaultRegistry,
        Transport: transport.DefaultTransport,
        Context:   context.Background(),
    }

    for _, o := range opts {
        o(&opt)
    }

    return opt
}

當時呢,也不是很明白newOptions這個構造函數爲何要這麼寫,可是後面在微信羣裏看到有人也再發相似的代碼問爲何要這麼寫,後來在羣裏討論的時候才知道了這是一種設計模式–函數式選項模式golang

可能你們看到如今也不是很明白我說的問題究竟是什麼,我把它簡單提煉一下。編程

咱們如今有一個結構體,定義以下:設計模式

type Option struct {
    A string
    B string
    C int
}

如今咱們須要爲其編寫一個構造函數,咱們可能會寫成下面這種方式:bash

func newOption(a, b string, c int) *Option {
    return &Option{
        A: a,
        B: b,
        C: c,
    }
}

上面的代碼很好理解,也是咱們一直在寫的。有什麼問題嗎?微信

咱們如今來思考如下兩個問題:閉包

  1. 咱們可能須要爲Option的字段指定默認值
  2. Option的字段成員可能會發生變動

2、選項模式

咱們先定義一個OptionFunc的函數類型

type OptionFunc func(*Option)

而後利用閉包爲每一個字段編寫一個設置值的With函數:

func WithA(a string) OptionFunc {
    return func(o *Option) {
        o.A = a
    }
}

func WithB(b string) OptionFunc {
    return func(o *Option) {
        o.B = b
    }
}

func WithC(c int) OptionFunc {
    return func(o *Option) {
        o.C = c
    }
}

而後,咱們定義一個默認的Option以下:

var (
    defaultOption = &Option{
        A: "A",
        B: "B",
        C: 100,
    }
)

最後編寫咱們新版的構造函數以下:

func newOption2(opts ...OptionFunc) (opt *Option) {
    opt = defaultOption
    for _, o := range opts {
        o(opt)
    }
    return
}

測試一下:

func main() {
    x := newOption("nazha", "小王子", 10)
    fmt.Println(x)
    x = newOption2()
    fmt.Println(x)
    x = newOption2(
        WithA("沙河娜扎"),
        WithC(250),
    )
    fmt.Println(x)
}

輸出:

&{nazha 小王子 10}
&{A B 100}
&{沙河娜扎 B 250}

這樣一個使用函數式選項設計模式的構造函數就實現了。這樣默認值也有了,之後再要爲Option添加新的字段也不會影響以前的代碼。

推薦閱讀:

Go 函數式選項模式

相關文章
相關標籤/搜索