• Functional Options


    这也是一种设计模式,简单的例子就是你对一个接口的设计在第一次真的能一应俱全吗?后期不会多参数等的调整吗?

    错误的例子,下面的例子每次加参数都十分痛苦。

    // package db
    
    func Connect(
      addr string,
      timeout time.Duration,
      caching bool,
    ) (*Connection, error) {
      // ...
    }
    
    // Timeout and caching must always be provided,
    // even if the user wants to use the default.
    
    db.Connect(addr, db.DefaultTimeout, db.DefaultCaching)
    db.Connect(addr, newTimeout, db.DefaultCaching)
    db.Connect(addr, db.DefaultTimeout, false /* caching */)
    db.Connect(addr, newTimeout, false /* caching */)

    那么总不能每次都改各种调用等吧,这完全没有工程性和可维护性。所以一些高手就想出了fucntional options。

    type options struct {
        timeout time.Duration
        caching bool
    }
    
    // Option overrides behavior of Connect.
    type Option interface {
        apply(*options)
    }
    
    type optionFunc func(*options)
    
    func (f optionFunc) apply(o *options) {
        // 这里就是执行withTimeout这边返回的OptionFunc的逻辑了===>也就是调用o.timeout = t
        f(o)
    }
    
    func WithTimeout(t time.Duration) Option {
        // 这里类似int(12),只是为了返回一个optionFunc
        return optionFunc(func(o *options) {
            o.timeout = t
        })
    }
    
    func WithCaching(cache bool) Option {
        return optionFunc(func(o *options) {
            o.caching = cache
        })
    }
    
    // Connect creates a connection.
    func Connect(
        addr string,
        opts ...Option,
    ) (*Connection, error) {
        options := options{
            // 理论上我们需要加上默认的参数,比如一个server
            timeout: defaultTimeout,
            caching: defaultCaching,
        }
    
        for _, o := range opts {
            o.apply(&options)
        }
    
        // ...
    }
    
    // Options must be provided only if needed.
    
    db.Connect(addr)
    db.Connect(addr, db.WithTimeout(newTimeout))
    db.Connect(addr, db.WithCaching(false))
    db.Connect(
    addr,
    db.WithCaching(false),
    db.WithTimeout(newTimeout),
    )

    例子二

    http://legendtkl.com/2016/11/05/code-scalability/

    func NewServer(addr string, options ...func(*Server)) (*Server, error) {
        srv := &Server{
            Addr:   addr,
        }
    
        for _, option := range options {
            option(srv)
        }
    
        return srv
    }
    
    func timeout(d time.Duration) func(*Server) {
        return func(srv *Server) {
            srv.timeout = d
        }
    }
    
    func tls(c *config) func(*Server) {
        return func(srv *Server) {
            Tls := loadConfig(c)
            srv.tls = Tls
        }
    }
    
    //使用
    src, err = NewServer("localhost:8080", timeout(1), tls(path/to/cert))

    原博还展示了一种似乎更便捷的维护handler方式,这样就可以避免我们每一次添加新的处理分散处理。

    这样我们只需先写一个hanler逻辑,再register,再调用mux相关使用即可。

    type Option struct {
        Key string
    }
    
    var mux map[string]func(option *Option) error
    
    func register(key string, f func(option *Option) error) error {
        if mux == nil {
            mux = make(map[string]func(option *Option) error)
        }
        if _, exist := mux[key]; exist {
            return errors.New("handler exist")
        }
        mux[key] = f
        return nil
    }
    
    func factory(option *Option) error {
        return mux[option.Key](option)
    }

    end

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    Codeforces 1237D. Balanced Playlist
    Codeforces 1237C2. Balanced Removals (Harder)
    使用excel计算指数平滑和移动平均
    HP滤波原理浅学
    第二章平稳时间序列模型——ACF和PACF和样本ACF/PACF
    第二章平稳时间序列模型——AR(p),MA(q),ARMA(p,q)模型及其平稳性
    第一章时间序列基础——差分方程和求解(二)
    R中的par()函数的参数
    你真的懂了R中的stem函数是如何绘制茎叶图的么?
    关于R中的mode()和class()的区别
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12795294.html
Copyright © 2020-2023  润新知