zoukankan      html  css  js  c++  java
  • (转)Golang functional options,优雅的初始化对象实例

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

    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,
    	}
    }

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

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

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

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

    type NewClientOptions func(c *Client)

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

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

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

    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
    	}
    }

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

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

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

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

    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,
    		)),
    	)

    转自:https://blog.csdn.net/liyunlong41/article/details/89048382

  • 相关阅读:
    [原译]Lambda高手之路第一部分
    阿里巴巴5月5日综合算法题详解
    [原译]Lambda高手之路第三部分
    [原译]多线程揭秘
    Leadtools控件变组件问题的解决方法
    写派生控件时不要随便override!
    关于foreach使用限制的一点误解
    WinForm中使用GDI+实现滚动动画
    注意:在SQL SERVER中使用NChar、NVarchar和NText
    局域网中禁止客户端用户直接访问服务器共享文件夹的简单解决方案
  • 原文地址:https://www.cnblogs.com/zhangmingcheng/p/14502485.html
Copyright © 2011-2022 走看看