返回顶部
首页 > 资讯 > 后端开发 > GO >详解Golang函数式选项(Functional Options)模式
  • 712
分享到

详解Golang函数式选项(Functional Options)模式

2024-04-02 19:04:59 712人浏览 八月长安
摘要

概览 最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写。 我们先来看一下源代码: type User struct { ID string N

概览

最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写。
我们先来看一下源代码:


type User struct {
	ID     string
	Name   string
	Age    int
	Email  string
	Phone  string
	Gender string
}

type Option func(*User)

func WithAge(age int) Option {
	return func(u *User) {
		u.Age = age
	}
}

func WithEmail(email string) Option {
	return func(u *User) {
		u.Email = email
	}
}

func WithPhone(phone string) Option {
	return func(u *User) {
		u.Phone = phone
	}
}

func WithGender(gender string) Option {
	return func(u *User) {
		u.Gender = gender
	}
}

func NewUser(id string, name string, options ...func(*User)) (*User, error) {
	user := User{
		ID:     id,
		Name:   name,
		Age:    0,
		Email:  "",
		Phone:  "",
		Gender: "female",
	}
	for _, option := range options {
		option(&user)
	}
	//...
	return &user, nil
}

func main() {
	user, err := NewUser("1", "Ada", WithAge(18), WithPhone("123456"))
	if err != nil {
		fmt.Printf("NewUser: err:%v", err)
	}
	fmt.Printf("NewUser Success")
}

当时呢,也不是很明白 NewUser 这个构造函数为什么要这么写,后来查看了资料才知道了这是一种设计模式函数式选项(functional options)模式

什么是函数式选项模式,为什么要这么写,这个编程模式解决了什么问题呢?

其实就是为了解决动态灵活的配置不同的参数的问题。

假如我们有一个需求:
在网站注册账号,有很多可选的选项,可填可不填。会根据你填的信息初始化你的 User 对象。

重载函数

如果你有 C++ 或者 Java 的编程基础,你的第一反应应该是函数重载。

但是因为 Golang 语言不像 C++ 一样支持重载函数,所以,你得用不同的函数名来应对不同的配置选项。

像这样:


func NewUserDefault(id string, name string) (*User, error) {
  return &User{ID: id, Name: name}, nil
}

func NewUserWithPhone(id string, name string, phone string) (*User, error) {
  return &User{ID: id, Name: name, Phone: phone}, nil
}

func NewUserWithEmail(id string, name string, email string) (*User, error) {
  return &User{ID: id, Name: name, Email: email}, nil
}

如果一共只有两三个参数的情况下,比较简单,但是更多的选项的组合就代码看起来很乱了。

配置化

这个时候我们可能会想到,配置化。
把所有可选的参数放到一个Config的struct中。


type Config struct {
    Age    int
    Email  string
    Phone  string
    Gender string
}

然后把Config放到User的struct中。


type User struct {
    ID   string
    Name string
    Conf *Config
}

于是,我们只需要一个 NewUser() 的函数了,在使用前需要构造 Config 对象。


func NewUser(id string, name string, conf *Config) (*User, error) {
    //...
}
//Using the default configuratrion
user, _ := NewUser("1", "Ada", nil)

conf := Config{Age:18, Phone: "123456"}
user2, _ := NewUser("2", "Bob", &conf)

这段代码看起来算是不错了,很多时候我使用的一些开源库也是这么写的。通过引入一个Config对象来解决多个参数的组合的问题。

Builder模式

有些经常使用Java的同学会想到Builder模式。

于是就可以以如下的方式来使用了:


user := new(UserBuilder).Create("1", "Ada").
  age(18).
  phone("123456").
  gender("female").
  Build()

需要引入一个抽象的UserBuilder对象,来包装User对象,最终Build一个User对象返回。

函数式选项模式

函数式选项模式 首先需要定义一个函数类型:


type Option func(*User)

然后,我们定义一组返回函数的函数:


func WithAge(age int) Option {
	return func(u *User) {
		u.Age = age
	}
}

func WithEmail(email string) Option {
	return func(u *User) {
		u.Email = email
	}
}

func WithPhone(phone string) Option {
	return func(u *User) {
		u.Phone = phone
	}
}

func WithGender(gender string) Option {
	return func(u *User) {
		u.Gender = gender
	}
}

这个模式和Builder模式的区别是,Builder模式返回的是 * User 对象,Functional Options 返回的是函数类型 func(* User)

上面这组代码传入一个参数,然后返回一个函数,返回的这个函数会设置自己的 User 参数。

这样我们就方便在 NewUser 里面统一初始化。循环对我们的函数类型执行调用操作。 option(&user)


func NewUser(id string, name string, options ...func(*User)) (*User, error) {
	user := User{
		ID:     id,
		Name:   name,
		Age:    0,
		Email:  "",
		Phone:  "",
		Gender: "female",
	}
	for _, option := range options {
		option(&user)
	}
	//...
	return &user, nil
}

调用方式如下:


user1, err := NewUser("1", "Ada")
user2, err := NewUser("2", "Bob", WithPhone("123456"), WithGender("male"))

这个看起来比较整洁和优雅,对外的接口只有一个NewUser。

相比于Builder模式,不需要引入一个Builder对象。

对比配置化的模式,也不需要引入一个新的Config。

总结

Golang 由于语言本身的特性,不支持函数重载,函数式选项 的编程模式在一定程度上解决了其他语言需要通过函数重载解决的问题。
函数式选项 编程有以下优点:

优点:

任意顺序传递参数支持默认值向后兼容性很容易维护和扩展

看了这么多,是不是想马上上手重构你之前的代码了。

虽然 函数式选项 编程模式有很多优点,但是设计模式的存在都是为了弥补语言特性的缺陷的一种手段。它是为了解决代码扩展性的问题,往往是通过增加抽象牺牲了简单性,切勿过度使用。有些简单的配置,就不需要设计的这么通用了。

函数式选项模式的使用场景有哪些呢:
我们一般用来配置一些基础的服务配置,比如MysqlRediskafka的配置,很多可选参数,可以方便动态灵活的配置想要配置的参数。

到此这篇关于golang函数式选项(Functional Options)模式的文章就介绍到这了,更多相关Golang函数式选项内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: 详解Golang函数式选项(Functional Options)模式

本文链接: https://lsjlt.com/news/160854.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解Golang函数式选项(Functional Options)模式
    概览 最近阅读源码的时候看到一段不错的代码,但是当时却不是非常理解为什么这么写。 我们先来看一下源代码: type User struct { ID string N...
    99+
    2024-04-02
  • GO 函数式选项模式(Functional Options Pattern)
    Golang 开发者遇到的许多问题之一是尝试将一个函数的参数设置为可选. 这是一个非常常见的用例, 有些对象应该使用一些基本的默认设置来开箱即用, 并且你偶尔可能需要提供一些更详细的...
    99+
    2024-04-02
  • ASP.NETCore中的Options选项模式
    1.前言 选项(Options)模式是对配置(Configuration)的功能的延伸。在12章(ASP.NET Core中的配置二)Configuration中有介绍过该功能(绑定...
    99+
    2024-04-02
  • Golang函数式选项模式怎么实现
    本篇内容主要讲解“Golang函数式选项模式怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang函数式选项模式怎么实现”吧!概览最近阅读源码的时候看到一段不错的代码,但是当时却不是...
    99+
    2023-06-22
  • ASP.NET Core中的Options选项模式怎么配置
    这篇文章主要介绍“ASP.NET Core中的Options选项模式怎么配置”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“ASP.NET Core中的Options选项模式怎么配...
    99+
    2023-06-29
  • 详解ASP.NET Core3.0 配置的Options模式
    上一章讲到了配置的用法及内部处理机制,对于配置,ASP.NET Core还提供了一种Options模式。 一、Options的使用 上一章有个配置的绑定的例子,可以将配置绑定...
    99+
    2022-06-07
    options net ASP.NET core ASP
  • Golang 函数设计模式的应用详解
    go语言函数式编程模式包括:命令模式:将操作封装成对象,实现请求延迟。策略模式:使用函数作为策略,动态更改算法。回调函数:作为参数传递给其他函数,灵活控制流程。这些模式通过函数作为一等公...
    99+
    2024-04-19
    golang 函数设计模式 go语言
  • ts 类型体操 Chainable Options 可链式选项示例详解
    目录问题答案传参option部分get问题 在JavaScript我们通常会使用到可串联(Chainable/Pipline)的函数构造一个对象,但是在Typescript中,你能合...
    99+
    2024-04-02
  • Golang函数错误处理的模式与反模式
    go 函数错误处理模式有:使用 errors.new() 创建错误、包装底层错误、返回 nil 表示无错误。反模式包括:使用魔数或字符串表示错误、隐式处理错误、忽略错误、延迟退出模式。最...
    99+
    2024-04-24
    golang 函数错误处理
  • Golang设计模式之原型模式详细讲解
    目录原型模式概念示例原型模式 原型是一种创建型设计模式, 使你能够复制对象, 甚至是复杂对象, 而又无需使代码依赖它们所属的类。 所有的原型类都必须有一个通用的接口, 使得即使在对象...
    99+
    2023-01-11
    Go原型模式 Go设计模式
  • Golang设计模式之单例模式详细讲解
    目录单例模式概念示例单例模式 单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但...
    99+
    2023-01-11
    Go单例模式 Go设计模式
  • golang函数的通用设计模式
    go 语言函数设计模式用于提高代码可读性、可维护性和可重用性,包括:输入/输出参数:允许函数通过参数修改调用方的值。返回多个值:简化代码,避免使用全局变量。函数作为参数:创建灵活、可定制...
    99+
    2024-04-26
    golang 设计模式 代码可读性
  • golang函数的错误处理模式
    在 go 中处理函数错误的常见模式有:返回错误:函数返回错误值,成功时为 nil,失败时为 error 类型。全局变量:使用全局变量存储错误值,以便函数轻松访问和使用错误值。恐慌:当错误...
    99+
    2024-05-04
    golang 错误处理
  • Golang设计模式中的桥接模式详细讲解
    目录桥接模式概念示例桥接模式 桥接是一种结构型设计模式, 可将业务逻辑或一个大类拆分为不同的层次结构, 从而能独立地进行开发。 层次结构中的第一层 (通常称为抽象部分) 将包含对第二...
    99+
    2023-01-11
    Go桥接模式 Go设计模式
  • Golang设计模式之适配器模式详细讲解
    目录适配器模式概念示例适配器模式 适配器是一种结构型设计模式, 它能使不兼容的对象能够相互合作。 适配器可担任两个对象间的封装器, 它会接收对于一个对象的调用, 并将其转换为另一个对...
    99+
    2023-01-11
    Go适配器模式 Go设计模式
  • 详解WPF的InkCanvas选择模式
    目录InkCanvas的选择效果InkCanvas选择模式的实现InkCanvas是WPF中进行墨迹绘制的控件,本文介绍下InkCanvas控件是如何进行选择操作的。文中有误的地方希...
    99+
    2024-04-02
  • 分布式系统中的 Golang 函数部署模式
    在分布式系统中部署 golang 函数,可采用两种模式:容器镜像:将函数代码打包成容器镜像,提供灵活性但管理容器较复杂。source:直接部署函数源代码,简单易用但可移植性受平台支持限制...
    99+
    2024-04-19
    golang 分布式系统
  • Golang设计模式中抽象工厂模式详细讲解
    目录抽象工厂模式概念示例抽象工厂模式 抽象工厂模式是一种创建型设计模式, 它能创建一系列相关的对象, 而无需指定其具体类。 抽象工厂定义了用于创建不同产品的接口, 但将实际的创建工...
    99+
    2023-01-11
    Go抽象工厂模式 Go设计模式
  • Python函数式编程中itertools模块详解
    目录容器与可迭代对象count() 函数cycle 函数repeat 函数enumerate 函数,添加序号accumulate 函数chain 与 groupby 函数zip_lo...
    99+
    2024-04-02
  • golang函数与管道通信的模式
    使用管道在 go 语言中进行函数间通信的模式有两种:生产者-消费者模式:生产者函数写入管道,消费者函数读取管道。工作池模式:一个函数创建工作管道,其他函数从管道中接收工作并执行。 Go...
    99+
    2024-05-01
    函数 golang 管道通信
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作