• 选项模式


    本文主要介绍了Go语言中函数式选项模式及该设计模式在实际编程中的应用。

    为什么需要函数式选项模式?

    最近看go-micro/options.go源码的时候,发现了一段关于服务注册的代码如下:

    type Options struct {
        Broker    broker.Broker
        Cmd       cmd.Cmd
        Client    client.Client
        Server    server.Server
        Registry  registry.Registry
        Transport transport.Transport
    
        // Before and After funcs
        BeforeStart []func() error
        BeforeStop  []func() error
        AfterStart  []func() error
        AfterStop   []func() error
    
        // Other options for implementations of the interface
        // can be stored in a context
        Context context.Context
    }
    
    func newOptions(opts ...Option) Options {
        opt := Options{
            Broker:    broker.DefaultBroker,
            Cmd:       cmd.DefaultCmd,
            Client:    client.DefaultClient,
            Server:    server.DefaultServer,
            Registry:  registry.DefaultRegistry,
            Transport: transport.DefaultTransport,
            Context:   context.Background(),
        }
    
        for _, o := range opts {
            o(&opt)
        }
    
        return opt
    }
    

    当时呢,也不是很明白newOptions这个构造函数为什么要这么写,但是后面在微信群里看到有人也再发类似的代码问为什么要这么写,后来在群里讨论的时候才知道了这是一种设计模式–函数式选项模式

    可能大家看到现在也不是很明白我说的问题到底是什么,我把它简单提炼一下。

    我们现在有一个结构体,定义如下:

    type Option struct {
    	A string
    	B string
    	C int
    }
    

    现在我们需要为其编写一个构造函数,我们可能会写成下面这种方式:

    func newOption(a, b string, c int) *Option {
    	return &Option{
    		A: a,
    		B: b,
    		C: c,
    	}
    }
    

    上面的代码很好理解,也是我们一直在写的。有什么问题吗?

    我们现在来思考以下两个问题:

    1. 我们可能需要为Option的字段指定默认值
    2. Option的字段成员可能会发生变更

    选项模式

    我们先定义一个OptionFunc的函数类型

    type OptionFunc func(*Option)
    

    然后利用闭包为每个字段编写一个设置值的With函数:

    func WithA(a string) OptionFunc {
    	return func(o *Option) {
    		o.A = a
    	}
    }
    
    func WithB(b string) OptionFunc {
    	return func(o *Option) {
    		o.B = b
    	}
    }
    
    func WithC(c int) OptionFunc {
    	return func(o *Option) {
    		o.C = c
    	}
    }
    

    然后,我们定义一个默认的Option如下:

    var (
    	defaultOption = &Option{
    		A: "A",
    		B: "B",
    		C: 100,
    	}
    )
    

    最后编写我们新版的构造函数如下:

    func newOption2(opts ...OptionFunc) (opt *Option) {
    	opt = defaultOption
    	for _, o := range opts {
    		o(opt)
    	}
    	return
    }
    

    测试一下:

    func main() {
    	x := newOption("nazha", "小王子", 10)
    	fmt.Println(x)
    	x = newOption2()
    	fmt.Println(x)
    	x = newOption2(
    		WithA("沙河娜扎"),
    		WithC(250),
    	)
    	fmt.Println(x)
    }
    

    输出:

    &{nazha 小王子 10}
    &{A B 100}
    &{沙河娜扎 B 250}
    

    这样一个使用函数式选项设计模式的构造函数就实现了。这样默认值也有了,以后再要为Option添加新的字段也不会影响之前的代码。

    推荐阅读:

    Go 函数式选项模式

  • 相关阅读:
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 貌似化学
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    Java 蓝桥杯 算法训练 字符串的展开 (JAVA语言实现)
    JAVA-蓝桥杯-算法训练-字符串变换
    Ceph:一个开源的 Linux PB 级分布式文件系统
    shell 脚本监控程序是否正在执行, 如果没有执行, 则自动启动该进程
  • 原文地址:https://www.cnblogs.com/Golanguage/p/12285459.html
Copyright © 2020-2023  润新知