go语言设计模式之函数式选项模式(代码片段)

dr-wei dr-wei     2023-05-06     313

关键词:

Go语言设计模式之函数式选项模式

本文主要介绍了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 函数式选项模式

golang函数式选项(functionaloptions)模式(代码片段)

...农在新加坡】,欢迎关注。个人博客网站:Golang函数式选项(FunctionalOptions)模式概览最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写。我们先来看一下源代码:typeUserstruct IDstring Nam... 查看详情

函数式编程之-模式匹配(patternmatching)(代码片段)

模式匹配在F#是非常普遍的,用来对某个值进行分支匹配或流程控制。模式匹配的基本用法模式匹配通过match...with表达式来完成,一个完整的模式表达式长下面的样子:match[something]with|pattern1->expression1|pattern2->expression2|pattern3... 查看详情

学习go语言之装饰器模式(代码片段)

一,首先理解装饰器模式:动态的给一个对象增加一些额外的职责,这是在软件设计原则上面,一个功能装饰另一个功能,每个功能遵循同一个接口是这个模式的特征。二,定义对象接口和装饰抽象类1typeIDecorateinterface2Do()345//装... 查看详情

python--函数之推导式(代码片段)

5.12推导式l=[]foriinrange(1,11):l.append(i)print(l)#用列表推导式(一行搞定)l=[iforiinrange(1,11)]print(l)列表推导式可分为两种模式:循环模式:[变量(加工的变量)for变量initerable(可迭代对象)]筛选模式:[变量(加工的变量)for变量initerable(可迭代对象... 查看详情

golang设计模式之选项模式(代码片段)

有时候一个函数会有很多参数,为了方便函数的使用,我们会给希望给一些参数设定默认值,调用时只需要传与默认值不同的参数即可,类似于python里面的默认参数和字典参数,虽然golang里面既没有默认参数也没有字典参数,但... 查看详情

go的选项模式

...个结构体如下定义:我们需要初始化结构体,如果是其他语言,函数支持默认参数:但是,go语言函数不支持默认参数,同时即使go语言支持默认参数,但是如果配置项过多,那么每一个配置项都得写一个默认参数,也不现实。... 查看详情

golang函数式选项(functionaloptions)模式(代码片段)

概览最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写。我们先来看一下源代码:typeUserstruct IDstring Namestring Ageint Emailstring Phonestring GenderstringtypeOptionfunc(*User)funcWithAge(ageint)Option returnfunc(u*Us... 查看详情

go中设计模式之结构型模式(代码片段)

外观模式1.定义:外部与一个子系统通信必须通过一个统一的对象进行,为子系统中的一组接口提供一致界面。2.代码示例://定义对外APItypeAPIinterfaceTest()funcNewAPI()APIreturnapiImplnewMod()typeapiImplstructmmodfunc(aapiImpl)Test()a.m.mod()//需要交... 查看详情

设计模式之单例模式(代码片段)

目录一、概念二、饿汉式实现三、懒汉式实现一四、懒汉式实现二1、双重判断2、指令重排3、可见性五、懒汉式实现三1、加载时机2、线程安全一、概念JVM中,单例对象只有一个实例存在。二、饿汉式实现publicclassSingletonprivatestat... 查看详情

单例设计模式之懒汉式(代码片段)

classSingletonprivatestaticSingletoninstance=null;privateSingleton()publicstaticSingletongetInstance()if(instance==null)synchronized(Singleton.class)if(instance==null)instance=newSingleton(); 查看详情

单例模式之懒汉式(代码片段)

单例模式之懒汉式:classLazyMan//单例模式之懒汉式,只有在需要的时候才被创建,//因为多个线程共享一个变量,所以会产生线程安全问题staticprivateLazyManlazyMan;/***因为要解决线程安全问题所以需要加上synchronized,但是这样*加上... 查看详情

java设计模式之单例模式与工厂模式(代码片段)

...🔥系列专栏:JavaSE精品总结文章目录  前言1、设计模式概念及分类2、单例模式2.1、饿汉式2.2、懒汉式2.2.1、懒汉式进阶版2.2.2、懒汉式之懒加载3、工厂模式3.1、书写实体类3.2、新建配置文件.properties3 查看详情

go设计模式—单例模式(代码片段)

        单例模式采用了饿汉式和懒汉式两种实现,个人其实更倾向于饿汉式的实现,简单,并且可以将问题及早暴露,懒汉式虽然支持延迟加载,但是这只是把冷启动时间放到了第一次使用的时候,... 查看详情

go语言之正则表达式(代码片段)

go语言之正则表达式//regexppackagemainimport("fmt""regexp")funcmain()//需要匹配的模式//reg:=regexp.MustCompile("\w+")正则表达式中的需要转义reg:=regexp.MustCompile(`^z.*1$`)//返回匹配到的结果result:=reg.FindAllString("zhangsan1",-1)f 查看详情

go语言学习-函数(代码片段)

函数Go不是一门纯函数式的编程语言,但是函数在Go中是“第一公民”,表现在:函数是一种类型,函数类型变量可以像其他类型变量一样使用,可以作为其他函数的参数或返回值,也可以直接调用执行。函数支持多值返回。支... 查看详情

设计模式-装饰者模式(go语言描述)(代码片段)

什么是装饰者模式好久没有更新设计模式系列的博客了,今天我们来聊一聊装饰者模式,用过java的同学肯定对装饰者模式非常熟悉,就算你不知道什么是装饰者模式这概念,你也一定在代码中经常用到这个模式,为什么这么说呢?大家... 查看详情

设计模式之单例模式详解(java)(代码片段)

目录一、单例模式1.1饿汉式1.2懒汉式1.3DCL懒汉式(双重检验锁)1.4静态内部类1.5枚举一、单例模式单例模式的实现方式有许多种,重点是以下五种:饿汉式、懒汉式、双重校验锁(DCL懒汉式)、静态内部类... 查看详情

设计模式之单例模式详解(java)(代码片段)

目录一、单例模式1.1饿汉式1.2懒汉式1.3DCL懒汉式(双重检验锁)1.4静态内部类1.5枚举一、单例模式单例模式的实现方式有许多种,重点是以下五种:饿汉式、懒汉式、双重校验锁(DCL懒汉式)、静态内部类... 查看详情