zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Oracle导出导入表空间创建
    ASP.NET 缓存 SqlCacheDependency 监视数据库表变化 让缓存更新的更及时更提高节能
    Silverlight在添加WCF服务引用时报错
    springboot中如何动态更换 配置文件 spring.profiles.active
    maven之根据profile动态切换resource
    java synchronized 关键字的锁升级过程
    子类中的方法和父类同名,但是参数不同,是重写(overload)不是覆盖(override)
    Java的协变(extends)和逆变(super),说白了都是子类的实例赋值给父类的变量
    Mybatis缓存
    [转]Spring MVC之 @PathVariable @CookieValue@RequestParam @RequestBody @RequestHeader@SessionAttributes, @ModelAttribute
  • 原文地址:https://www.cnblogs.com/CherryTab/p/12795294.html
Copyright © 2011-2022 走看看