golang functional options,优雅的初始化对象实例

系统管理员 2022-02-23 02:08 252阅读 0赞

当我们定义了一个对象时,一般会创建一个方法方便外部初始化一个实例。如下面的例子:

  1. type Client struct {
  2. timeout int64
  3. dialFunc func() error
  4. healthCheck func() bool
  5. }
  6. func NewClient(timeout int64, dialFunc func() error, healthCheck func() bool) *Client {
  7. return &Client{
  8. timeout: timeout,
  9. dialFunc: dialFunc,
  10. healthCheck: healthCheck,
  11. }
  12. }

外部调用NewClient来获取一个实例,NewClient方法需要给Client结构体每个参数都赋值,如果Client对象的参数有几十个的话,那么调用NewClient需要传入几十个参数,而且如果用户只是要更改其中一个参数,其他参数都想用默认的,也需要传入所有参数,非常的不方便。

优化的方法一种可以对每个参数设置一个Set方法,NewClient中每个参数都设置默认值,外部调用完NewClient后再调用SetXX方法。

如果想直接在NewClient中就一次性配置好,可以通过functional option来实现:

我们先定义配置选项option,option是一个func,入参是*Client实例,在里面我们可以修改实例的值。

  1. type NewClientOptions func(c *Client)

然后我们修改NewClient方法的入参为不定长的option,我们先创建一个实例,值都是默认值,然后调用option,修改实例的值。

  1. func NewClient2(opts ...NewClientOptions) *Client {
  2. client := &Client{
  3. timeout: defaultTimeout,
  4. dialFunc: defaultDialFunc,
  5. healthCheck: defaultHealthCheckFunc,
  6. }
  7. for _, opt := range opts {
  8. opt(client) //opt是个方法,入参是*Client,内部会修改client的值
  9. }
  10. return client
  11. }

最后我们定义几个option方法:

  1. func WithTimeout(timeout int64) NewClientOptions {
  2. return func(c *Client) {
  3. c.timeout = timeout
  4. }
  5. }
  6. func WithHealthCheck(healthCheck func() bool) NewClientOptions {
  7. return func(c *Client) {
  8. c.healthCheck = healthCheck
  9. }
  10. }
  11. func WithDial(dialFunc func() error) NewClientOptions {
  12. return func(c *Client) {
  13. c.dialFunc = dialFunc
  14. }
  15. }

这样外部就可以更简单的调用NewClient方法了,我们自己定义一个myHealthCheckFunc,并通过WithHealthCheck包一下,然后作为参数传入就行了。

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

创建的client实例中timeout和healthCheck是我们自己定义的,而dialFunc是用默认的。

其实这种通过传入func来配置参数的方式是比较常见的,比如grpc在建立连接时的Dial方法,其实就是使用的这种方式。

  1. grpcClient, err = grpc.Dial(
  2. serviceTarget(target),
  3. grpc.WithBalancer(b),
  4. grpc.WithCompressor(grpc.NewGZIPCompressor()),
  5. grpc.WithDecompressor(grpc.NewGZIPDecompressor()),
  6. grpc.WithDefaultCallOptions(grpc.FailFast(false)),
  7. grpc.WithInsecure(),
  8. grpc.WithBlock(),
  9. grpc.WithTimeout(time.Second*5),
  10. grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(
  11. otgrpc.OpenTracingClientInterceptor(opentracing.GlobalTracer(), otgrpc.LogPayloads()),
  12. unaryClientInterceptor,
  13. )),
  14. )

发表评论

表情:
评论列表 (有 0 条评论,252人围观)

还没有评论,来说两句吧...

相关阅读