Golang - 选项模式 vs 构建器模式

news2025/1/11 7:02:36

在使用Golang创建复杂对象时,常用的两种模式是选项模式(Options pattern)和构建器模式(Builder pattern)。这两种模式各有优缺点,选择适合项目需求的模式取决于具体情况。

问题

假设我们想创建一个具有许多可选参数的复杂对象。一种方法是创建一个构造函数,该构造函数接受所有参数,并为可选参数提供默认值。然而,这种方法有一些缺点:

  1. 很难记住参数的顺序。
  2. 很难知道哪些参数是可选的,哪些是必需的。
  3. 构造函数可能会变得很长,难以阅读。

解决方案:选项模式

选项模式可以用于创建具有许多可选参数的对象。在这种模式下,我们定义一个包含可选参数的结构体,并提供设置这些参数的方法。相比构建器模式,这种模式可以更简洁,并且适用于参数较少的对象。

示例

在Golang中,可以使用函数选项(functional options)来实现选项模式。函数选项是以结构体作为参数,并返回修改后的结构体的函数。以下是使用选项模式创建披萨对象的示例代码:

type Pizza struct {
    dough     string
    sauce     string
    cheese    string
    toppings  []string
}

type PizzaOptions struct {
    Dough     string
    Sauce     string
    Cheese    string
    Toppings  []string
}

type PizzaOption func(*PizzaOptions)

func WithDough(dough string) PizzaOption {
    return func(po *PizzaOptions) {
        po.Dough = dough
    }
}

func WithSauce(sauce string) PizzaOption {
    return func(po *PizzaOptions) {
        po.Sauce = sauce
    }
}

func WithCheese(cheese string) PizzaOption {
    return func(po *PizzaOptions) {
        po.Cheese = cheese
    }
}

func WithToppings(toppings []string) PizzaOption {
    return func(po *PizzaOptions) {
        po.Toppings = toppings
    }
}

func NewPizza(options ...PizzaOption) *Pizza {
    opts := &PizzaOptions{}
    for _, option := range options {
        option(opts)
    }
    pizza := &Pizza{
        dough: opts.Dough,
        sauce: opts.Sauce,
        cheese: opts.Cheese,
        toppings: opts.Toppings,
    }
    return pizza
}

在这个例子中,我们定义了Pizza结构体和PizzaOptions结构体,其中PizzaOptions是一个包含可选参数的结构体。然后,我们定义了一系列函数来设置每个选项,比如WithDoughWithSauceWithToppings。这些函数返回一个PizzaOption,用于设置PizzaOptions结构体上对应的字段。最后,我们定义了一个NewPizza函数,它接受任意数量的PizzaOptions参数,并构造一个Pizza对象。

func main() {
   pizza := NewPizza(
      WithDough("Regular"),
      WithSauce("Tomato"),
      WithCheese("Mozzarella"),
      WithToppings([]string{"Pepperoni", "Olives", "Mushrooms"}),
   )

   println(pizza.dough)
   println(pizza.sauce)
   println(pizza.cheese)
   println(pizza.toppings)
}

Options模式可以是Builder模式的一个很好替代方案,用于创建具有许多可选参数的对象,特别是当对象的参数较少时。然而,对于具有许多参数的对象来说,Options模式可能变得笨拙,因为需要设置所有选项的函数数量可能会很大。

在Golang标准库中的使用

Options模式在Golang标准库中被用于创建诸如http.Request对象之类的对象,该对象具有许多可选参数。http.NewRequest函数接受方法、URL和可选的headers和body等参数,返回一个新的http.Request对象。headers和body是可选参数,可以使用函数选项来设置。

替代方案:Builder模式

Builder模式通过将复杂对象的构建与其表示分离,提供了对这些问题的解决方案。Builder模式涉及以下组件:

  1. Builder接口,定义构建对象的步骤。
  2. ConcreteBuilder结构体,实现Builder接口并提供构建对象的方法。
  3. Director结构体,使用Builder来构建对象。

示例

以下是在Golang中使用Builder模式实现的示例,使用了文章中提到的pizza对象:

type Pizza struct {
    dough     string
    sauce     string
    cheese    string
    toppings  []string
}

type PizzaBuilder interface {
    SetDough(string) PizzaBuilder
    SetSauce(string) PizzaBuilder
    SetCheese(string) PizzaBuilder
    SetToppings([]string) PizzaBuilder
    Build() *Pizza
}

type ConcretePizzaBuilder struct {
    pizza *Pizza
}

func NewConcretePizzaBuilder() *ConcretePizzaBuilder {
    return &ConcretePizzaBuilder{pizza: &Pizza{}}
}

func (cpb *ConcretePizzaBuilder) SetDough(dough string) PizzaBuilder {
    cpb.pizza.dough = dough
    return cpb
}

func (cpb *ConcretePizzaBuilder) SetSauce(sauce string) PizzaBuilder {
    cpb.pizza.sauce = sauce
    return cpb
}

func (cpb *ConcretePizzaBuilder) SetCheese(cheese string) PizzaBuilder {
    cpb.pizza.cheese = cheese
    return cpb
}

func (cpb *ConcretePizzaBuilder) SetToppings(toppings []string) PizzaBuilder {
    cpb.pizza.toppings = toppings
    return cpb
}

func (cpb *ConcretePizzaBuilder) Build() *Pizza {
    return cpb.pizza
}

type Director struct {
    builder PizzaBuilder
}

func NewDirector(builder PizzaBuilder) *Director {
    return &Director{builder: builder}
}

func (d *Director) Construct() *Pizza {
    return d.builder.SetDough("Thin Crust").SetSauce("Tomato").SetCheese("Mozzarella").SetToppings([]string{"Mushrooms", "Olives", "Onions"}).Build()
}

在这个示例中,我们定义了Pizza结构体和PizzaBuilder接口。ConcretePizzaBuilder结构体实现了PizzaBuilder接口,并提供了构建Pizza对象的方法。Director结构体使用PizzaBuilder来构建Pizza对象。Director结构体并不是严格必需的,但它提供了一种简化构建Pizza对象过程的方式。

我们可以使用DirectorConcretePizzaBuilder来创建一个Pizza对象,如下所示:

builder := NewConcretePizzaBuilder()
director := NewDirector(builder)
pizza := director.Construct()

这将创建一个具有以下属性的Pizza对象:

  • Dough: Thin Crust
  • Sauce: Tomato
  • Cheese: Mozzarella
  • Toppings: Mushrooms, Olives, Onions

请注意,我们只需要指定要更改的属性。所有其他属性都被设置为默认值。这使得创建具有许多可选参数的复杂对象变得更容易,无需记住参数的顺序以及哪些参数是可选的,哪些是必需的。

在 Golang 标准库中的使用

构建器模式并未在 Golang 标准库中使用,但在 Golang 应用程序中,它是一种常用的模式,用于创建具有许多可选参数的复杂对象。Options 模式也被用作 Golang 应用程序中的替代方案,用于创建具有许多可选参数的对象。

结论

Options 模式是 Builder 模式的一种替代方案,可用于创建具有许多可选参数的对象。它比 Builder 模式更简洁,但对于具有许多参数的对象可能会变得笨重。在 Golang 中,可以使用函数选项来实现 Options 模式。

Builder 模式是一种强大的模式,可以用于创建具有许多可选参数的复杂对象。它将对象的构建与表示分离,并提供了一种使用相同构建过程创建同一对象的不同表示的方式。在 Golang 中,Builder 模式可用于轻松创建复杂对象。

参考资料

  • “Design Patterns: Elements of Reusable Object-Oriented Software”(《设计模式:可复用面向对象软件的基础》)Erich Gamma、John Vlissides、Ralph Johnson、Richard Helm著

如果你喜欢我的文章,点赞,关注,转发!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【HTTP 协议】掌握 Web 的核心技术

哈喽,大家好~我是你们的老朋友:保护小周ღ 谈起 HTTP 协议(超文本传输协议),不知道大家第一次是从什么地方了解到这个协议的呢?在真实的网络环境中网络协议的种类非常多,其中有一些耳熟能详的…

GBASE南大通用5月份公司动态一览

产品动态 5月初,GBASE南大通用两款新产品:GBase 8c V5.0和GBase 8s V8.8.5于鲲鹏开发者大会主论坛商业发行版联合发布仪式上正式发布。新版本与上一版本功能特性保持兼容,并在算子能力、用户级别审计、兼容性等方面全面增强,支持一…

最新版本 Stable Diffusion 开源 AI 绘画工具之微调模型篇

✨ 目录 🎈 模型种类🎈 变分自动编码器 / VAE🎈 美学梯度 / Aesthetic Gradients🎈 大型语言模型的低阶自适应 / LoRA🎈 超网络模型 / Hypernetwork🎈 微调模型 / LyCORIS 🎈 模型种类 当你打开…

jacoco检测功能或自动化测试覆盖率

参考文档:http://t.csdn.cn/QqCSh http://t.csdn.cn/HonVL 目录 下载jacoco 启动jacocoagent监控被测项目 执行手工测试 生成exec文件 生成report报告 jacoco代码覆盖率报告分析 下载jacoco http://t.csdn.cn/HonVL 我下载的最新的 jacoco-0.8.10.zip 下…

虚拟化技术 — Cgroups 与 Namespaces 支撑实现的操作系统虚拟化

目录 文章目录 目录操作系统虚拟化(容器技术)的发展历程ChrootCgroupsCgroup SubsystemsCgroup FilesystemCgroup HierarchyCgroups 的操作规则Cgroups 的代码实现 NamespacesUTS namespacePID namespaceIPC namespaceMount namespaceNetwork namespaceU…

mysql order by 索引问题综合分析

一,文章1 Mysql-索引失效 order by优化_orderby索引失效_zyk1.的博客-CSDN博客 总结: 0,索引 与 查询条件 与 排序字段关系,Using filesort出现场景 1.联合索引,最左匹配原则,不仅查询条件需要遵循&…

vivado FIFO的Standard 和 FWFT模式

vivado FIFO的Standard 和 FWFT模式 Standard 模式读操作 对于标准 FIFO 读取操作,在断言读有效后,如果 FIFO 非空,存储在FIFO中的下一个数据被驱动到输出总线(dout)上和VALID标志有效。 下图显示标准模式下的读数据…

ChatGPT介绍与使用场景

ChatGPT是OpenAI开发的一款基于GPT-3和GPT-4的人工智能聊天机器人。“GPT"代表的是"Generative Pre-trained Transformer”,这是一种深度学习技术,使用人工神经网络来生成类似人类的文本。 ChatGPT能够处理各种对话任务,包括回答问…

教您如何快速自助搭建一个元宇宙场景

【导语】 在数字化时代,营销方式正经历着巨大的变革。而在这场变革的浪潮中,元宇宙编辑器凭借其独特的元宇宙展厅解决方案,为企业和个人提供了快速、简便的自助搭建元宇宙场景的机会。 今天,让我们一起走进元宇宙编辑器的世界&…

如何将Windows 7系统镜像部署到不同的硬件计算机?

案例:将Windows 7系统镜像恢复到另一台电脑 “我有一台运行 Windows 7 的电脑,我已经创建了一个系统镜像并希望将其加载到另一台电脑上。但是,当我运行恢复控制台时,我不断收到错误消息。这让我想知道是否可以创建 Windows 7 系…

前端面试技巧?第一手面试真题!

面试有哪些套路和技巧? 第一次去面试,该注意什么? 怎么说话能打动面试官,成功入职? 当你褪去青涩,将头发梳成大人模样走向面试之路时,你们的搜索记录和行为早已暴露了自己内心状态&#xff1a…

数据结构和算法的基本概念

数据结构概念 1.数据:所有能输入计算机且能被计算机处理的符号总称 2.数据元素:是数据的基本单位,表示数据集合中的一个个体。 3 .数据项:数据元素中有独立含义的最小单位。 数据结构:相互之间存在一定关系的数据元素的…

Layui时间选择设置只能选择整点半点,并隐藏秒钟部分

文章目录 1.整点半点选择2.隐藏秒选择部分3.默认值处理3.1 操作done函数3.2 操作ready函数 1.整点半点选择 处理思路:通过循环将使用不到的时间点去除掉,关键代码位于ready函数 //选择起止时间 layui.laydate.render({elem: .laydate-times,type: &quo…

第五章 Electron|Node 使用cheerio 爬虫

一、cheerio是什么可以做什么 👇 👇 👇 Cheerio是一个快速、灵活且精益的jQuery核心实现,用于在Node.js环境中解析HTML文档。它可以帮助您在服务器端轻松地从HTML文档中提取数据,比如从网页中提取文章标题、内容、图片…

【JVM】.class文件如何在JVM中运行的?

一、先认识JVM的组成 java虚拟机整体包括:类加载系统、运行时数据区、执行引擎、垃圾回收器。 (1)方法区:线程共享,存储Class信息、常量、静态变量等等; jdk1.6~1.7时称为永久代,存储常量、Cla…

js常见面试题整理

1:JavaScript 有哪些数据类型 答: JavaScript 的数据类型分为原始类型和对象类型。 原始类型有 7 种,分别是: BooleanNumberBigIntStringNullUndefinedSymbol 对象类型(也称引用类型)是一个泛称&#x…

vue3 中使用indexDb

1.indexDb.js const indexDB window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB; class IndexDBCache {// 构造函数constructor() {this._db null; //数据库this._transaction null; //事务this._request null;this._dbName "loginInfoDb"; …

API ‘variantOutput.getPackageLibrary()‘已过时的解决方法

一个发布到maven central的android库项目,为了方便管理,在build.gradle文件中加入了打包处理的一段脚本: //生成aarlibraryVariants.all { variant ->def name "library-${versionMajor}.${versionMinor}.${versionPatch}.aar"…

VUE 3.0 + NGINX + Hls.js + OBS -- 直播推拉流、流视频播放

🛴🛴前言: 该 Demo 基于 OBS推流 Nginx Vue 3.0 Nplayer.js hls.js ,目的只是实现流媒体播放,以及简易推拉流直播。 文章目录 前端组件 NPlayer.js安装 nplayer.js 流视频播放页面元素初始化播放器清晰度控件样式…

D*算法详解 (D星算法 / Dynamic A*算法/ Dstar算法)(死循环解决)

所需先验知识(没有也无大碍,只是了解的话会对D*的理解有帮助):A*算法/ Dijkstra算法 何为D*算法 Dijkstra算法是无启发的寻找图中两节点的最短连接路径的算法,A*算法则是在Dijkstra算法的基础上加入了启发函数h(x)&am…