Golang functional options

When we define an object, usually it creates a convenient method to initialize an instance external. As in the following example:


type Client struct {
	timeout     int64
	dialFunc    func() error
	healthCheck func() bool
}
 
func NewClient(timeout int64, dialFunc func() error, healthCheck func() bool) *Client {
	return &Client{
		timeout:     timeout,
		dialFunc:    dialFunc,
		healthCheck: healthCheck,
	}
}

External calls NewClientto get an instance, NewClientthe method needs to Client structure Each parameter assignment, if the parameter Client object There are dozens, then call the NewClientneed to pass dozens of parameters, but if you just want to change one parameter, other parameters want to use the default, also you need to pass all parameters, very inconvenient.

Optimization can set up a method for each parameter Set method , NewClienteach parameter are set to default values, complete external call NewClientafter call SetXX method .

If you are interested in NewClientthe on-time configuration, and can be achieved through functional option:

We first define configuration options option, optionit is a func, to the Senate is *Clientan example, we can modify the value of an instance in it.

type NewClientOptions func(c *Client)

Then we modify the NewClientapproach to the Senate as a variable length option, we first create an instance, the values are the default values, and then call option, modify the value of the instance.

func NewClient2(opts ...NewClientOptions) *Client {
	client := &Client{
		timeout:     defaultTimeout,
		dialFunc:    defaultDialFunc,
		healthCheck: defaultHealthCheckFunc,
	}
	for _, opt := range opts {
		opt(client) //opt是个方法,入参是*Client,内部会修改client的值
	}
	return client
}

Finally, we define several option methods:

func WithTimeout(timeout int64) NewClientOptions {
	return func(c *Client) {
		c.timeout = timeout
	}
}
 
func WithHealthCheck(healthCheck func() bool) NewClientOptions {
	return func(c *Client) {
		c.healthCheck = healthCheck
	}
}
 
func WithDial(dialFunc func() error) NewClientOptions {
	return func(c *Client) {
		c.dialFunc = dialFunc
	}
}

Such external calls can be simpler NewClientmethod, and a definition of our own myHealthCheckFunc, and through WithHealthCheckpackage it, and then passed as a parameter on the line.

client := NewClient2(WithHealthCheck(myHealthCheckFunc), WithTimeout(10))

Client instances created timeoutand healthCheckour own definition, which dialFuncis the default.

In fact, by passing this funcway it is more common configuration parameters, such as grpcwhen establishing a connection Dialmethod, this approach is actually used.

grpcClient, err = grpc.Dial(
		serviceTarget(target),
		grpc.WithBalancer(b),
		grpc.WithCompressor(grpc.NewGZIPCompressor()),
		grpc.WithDecompressor(grpc.NewGZIPDecompressor()),
		grpc.WithDefaultCallOptions(grpc.FailFast(false)),
		grpc.WithInsecure(),
		grpc.WithBlock(),
		grpc.WithTimeout(time.Second*5),
		grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(
			otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer(), otgrpc.LogPayloads()),
			unaryClientInterceptor,
		)),
	)
Published 158 original articles · won praise 119 · views 810 000 +

Guess you like

Origin blog.csdn.net/u013474436/article/details/104537781
Recommended