go設置函數默認參數(函數選項模式)

在日常開發中,我們有時候需要使用默認設置,但有時候需要提供自定義設置 結構體/類,在Java我們可以使用無參、有參構造函數來實現,在PHP中我們也可以使用構造函數來實現(如 public function __construct($isCName = false, $securityToken = NULL, $requestProxy = NULL))。但在golang中無法這樣做,不過我們可以使用另外一種方式優雅的實現。


1.舉例

在這之前,我們在golang中大多是使用以下方式來實現的:

type ExampleClient struct {
	Name string
	Job int
}

func NewExampleClient(name, job string) ExampleClient {
	if name != "" {
		name = "default"
	}
	
	if job != "" {
		job = "default"
	}
	
	return ExampleClient{
		Name: name,
		Job:  job,
	}
}

這種方式侵入性比較強,如果此時我們需要增加一個超時參數或其他更多參數,那麼需要在原代碼基礎上做很多的修改。


2.實現默認參數

在使用go-micro的過程中,發現其初始化服務配置的方式如下👇

func main() {
	sr := micro.NewService()
	//或
	sr := micro.NewService(
		micro.Name("xxx.xxx.xxx"),
		micro.Address("192.168.1.1"),
		)
}

進入到micro.NewService中,可以看到在初始化的過程中都是以type Option func(*Options)類型的函數作爲參數,並調用newOptions方法👇

type Option func(*Options)

// NewService creates and returns a new Service based on the packages within.
func NewService(opts ...Option) Service {
	return newService(opts...)
}

func newService(opts ...Option) Service {
	options := newOptions(opts...)

	// service name
	serviceName := options.Server.Options().Name

	// wrap client to inject From-Service header on any calls
	options.Client = wrapper.FromService(serviceName, options.Client)

	return &service{
		opts: options,
	}
}

我們再接着進入到micro.newOptions中查看👇

type Options struct {
	Broker    broker.Broker
	Registry  registry.Registry
	...
}

func newOptions(opts ...Option) Options {
	opt := Options{
		Broker:    broker.DefaultBroker,
		Registry:  registry.DefaultRegistry,
		...
	}

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

	return opt
}

// Name of the service
func Name(n string) Option {
	return func(o *Options) {
		o.Server.Init(server.Name(n))
	}
}

// Address sets the address of the server
func Address(addr string) Option {
	return func(o *Options) {
		o.Server.Init(server.Address(addr))
	}
}

現在,我們知道了如何實現函數默認參數,最重要的步驟如下👇

//定義結構體
type ExampleClient struct {
	Name string
	Job string
}

//定義配置選項函數(關鍵)
type Option func(*ExampleClient)
func SetName(name string) Option {// 返回一個Option類型的函數(閉包):接受ExampleClient類型指針參數並修改之
	return func(this *ExampleClient) {
		this.Name = name
	}
}

//應用函數選項配置
func NewExampleClient(opts ...Option) ExampleClient{
	// 初始化默認值
	defaultClient := ExampleClient{
		Name: "default",
		Job:  "default",
	}

	// 依次調用opts函數列表中的函數,爲結構體成員賦值
	for _, o := range opts {
		o(&defaultClient)
	}
	
	return defaultClient
}

這樣利用閉包的特性,當我們需要額外添加參數時,只需要增加配置選項函數即可,拓展性很強。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章