[Go] Option选项设计模式 — — 编程方式基础入门

news2025/6/3 12:50:03

[Go] Option选项设计模式 — — 编程方式基础入门

全部代码地址,欢迎⭐️

  • Github:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-option

1 介绍

在 Go 开发中,我们经常遇到需要处理多参数配置的场景。传统方法存在诸多痛点,例如:

问题一:参数过多且顺序敏感,导致我们调用时难以阅读,不知道每个参数背后对应的含义

// 参数过多且顺序敏感
func NewServer(addr string, port int, timeout time.Duration, maxConns int, tls bool) {
    // ...
}

// 调用时难以阅读
srv := NewServer(":8080", 3306, 10*time.Second, 100, true)

问题二:新增改动,需要修改所有调用点

// 新增参数需修改所有调用点
func NewServer(..., enableLog bool) // 新增参数破坏现有代码

这时就可以使用Go自带的Option方式编程。

Go Option主要有以下优势:

  • ✅ 自描述性:命名选项明确参数含义
  • ✅ 安全扩展:新增选项不影响现有调用
  • ✅ 默认值处理:自动应用合理默认配置
  • ✅ 参数验证:可在选项函数中实现验证逻辑
  • ✅ 顺序无关:任意顺序传递选项参数

2 基础入门

2.1 定义类结构以及Option

// 定义配置结构体
type Config struct {
    Timeout time.Duration
    MaxConn int
    TLS     bool
}

// 定义选项函数类型
type Option func(*Config)

// 步骤3:实现构造函数
func NewConfig(opts ...Option) *Config {
    // 设置默认值
    cfg := &Config{
        Timeout: 10 * time.Second,
        MaxConn: 100,
        TLS:     false,
    }
    
    // 应用所有选项
    for _, opt := range opts {
    	//因为opt本身就是func,所以这里相当于调用函数,入参为cfg struct
        opt(cfg)
    }
    return cfg
}

2.2 定义选项函数Withxx

// 带参数的选项
func WithTimeout(t time.Duration) Option {
    return func(c *Config) {
        c.Timeout = t
    }
}

// 无参数的选项(开关功能)
func WithTLS() Option {
    return func(c *Config) {
        c.TLS = true
    }
}

// 带验证的选项
func WithMaxConn(n int) Option {
    return func(c *Config) {
        if n > 0 {
            c.MaxConn = n
        } // 否则保持默认值
    }
}

2.3 使用

// 只使用默认值
defaultCfg := NewConfig()

// 覆盖部分默认值
customCfg := NewConfig(
    WithTimeout(30*time.Second),
    WithMaxConn(200),
)

// 启用特定功能
secureCfg := NewConfig(
    WithTLS(),
    WithTimeout(15*time.Second),
)

全部代码

package main

import (
	"fmt"
	"time"
)

// 定义配置结构体
type Config struct {
	Timeout time.Duration
	MaxConn int
	TLS     bool
}

// 定义选项函数类型
type Option func(*Config)

// 实现构造函数
func NewConfig(opts ...Option) *Config {
	// 设置默认值
	cfg := &Config{
		Timeout: 10 * time.Second,
		MaxConn: 100,
		TLS:     false,
	}

	// 应用所有选项
	for _, opt := range opts {
		opt(cfg)
	}
	return cfg
}

// 带参数的选项
func WithTimeout(t time.Duration) Option {
	return func(c *Config) {
		c.Timeout = t
	}
}

// 无参数的选项(开关功能)
func WithTLS() Option {
	return func(c *Config) {
		c.TLS = true
	}
}

// 带验证的选项
func WithMaxConn(n int) Option {
	return func(c *Config) {
		if n > 0 {
			c.MaxConn = n
		} // 否则保持默认值
	}
}

func main() {
	// 启用特定功能
	secureCfg := NewConfig(
		WithTLS(),
		WithTimeout(15*time.Second),
	)
	fmt.Println(secureCfg)
}

3. 实战使用

Go Option方式可以用在数据库配置、HTTP服务配置、客户端连接配置、日志系统配置等。这里以HTTP服务配置为例。

package main

import (
	"fmt"
	"time"
)

type Option func(*ServerConfig)

type ServerConfig struct {
	Addr        string
	ReadTimeout time.Duration
	IdleTimeout time.Duration
	EnableCORS  bool
}

func NewServer(addr string, opts ...Option) *ServerConfig {
	cfg := &ServerConfig{
		Addr:        addr,
		ReadTimeout: 5 * time.Second,
		IdleTimeout: 30 * time.Second,
	}

	for _, opt := range opts {
		opt(cfg)
	}
	return cfg
}

// 组合选项:同时设置多个相关参数
func WithTimeouts(read, idle time.Duration) Option {
	return func(s *ServerConfig) {
		s.ReadTimeout = read
		s.IdleTimeout = idle
	}
}

func EnableCORS() Option {
	return func(s *ServerConfig) {
		s.EnableCORS = true
	}
}

func main() {
	// 使用示例
	server := NewServer(
		":8080",
		WithTimeouts(10*time.Second, 60*time.Second),
		EnableCORS(),
	)
	fmt.Println(server)
}

4. 进阶(Option与链式调用结合)

在 Go 中我们可以结合 Option 模式和链式调用可以创建高度可读、灵活的 API,实现优雅编程。这种方式尤其适用于复杂对象的配置。
核心思想:

  1. Option 模式:使用函数闭包封装配置逻辑
  2. 链式调用:每个配置方法返回对象本身,支持连续调用
package main

import "fmt"

// 目标配置对象
type Server struct {
	host    string
	port    int
	timeout int // 秒
	tls     bool
}

// Option 函数类型:接收 *Server 的闭包
type Option func(*Server)

// 链式包装器(关键结构)
type ServerBuilder struct {
	options []Option
}

// 创建 Builder 实例
func NewBuilder() *ServerBuilder {
	return &ServerBuilder{}
}

// 链式方法:添加配置选项
func (b *ServerBuilder) WithHost(host string) *ServerBuilder {
	b.options = append(b.options, func(s *Server) {
		s.host = host
	})
	return b
}

func (b *ServerBuilder) WithPort(port int) *ServerBuilder {
	b.options = append(b.options, func(s *Server) {
		s.port = port
	})
	return b
}

func (b *ServerBuilder) WithTimeout(timeout int) *ServerBuilder {
	b.options = append(b.options, func(s *Server) {
		s.timeout = timeout
	})
	return b
}

func (b *ServerBuilder) WithTLS(tls bool) *ServerBuilder {
	b.options = append(b.options, func(s *Server) {
		s.tls = tls
	})
	return b
}

func (b *ServerBuilder) Build() *Server {
	// 设置默认值
	s := &Server{
		host:    "localhost",
		port:    8080,
		timeout: 30,
	}

	// 应用所有配置函数
	for _, option := range b.options {
		option(s)
	}
	return s
}

func main() {
	server := NewBuilder().
		WithHost("api.ziyi.com").
		WithPort(443).
		WithTimeout(60).
		WithTLS(true).
		Build()

	fmt.Printf("%+v\n", server)
	// 输出:&{host:api.example.com port:443 timeout:60 tls:true}
}

总结

①概念:

Option 模式是 Go 语言中处理复杂配置的优雅解决方案,它通过:

  • 功能选项(Functional Options)实现灵活的配置扩展
  • 默认值机制减少调用方负担
  • 命名参数提高代码可读性
  • 零成本扩展支持未来需求变化

②使用场景:

  1. 对象需要 5个以上 配置参数时
  2. 超过 3个可选 配置项时
  3. 配置可能有 合理默认值 时
  4. 需要 高频扩展 配置的场景
  5. 开源库/框架中需要提供 友好API 时

实践tips:可以从简单的配置对象开始,当可选参数超过3个或发现构造函数参数过多时,可考虑重构为Option模式。

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

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

相关文章

【笔记】开源通用人工智能代理 Suna 部署全流程准备清单(Windows 系统)

#工作记录 一、基础工具与环境 开发工具 Git 或 GitHub Desktop(代码管理)Docker Desktop(需启用 WSL2,容器化部署)Python 3.11(推荐版本,需添加到系统环境变量)Node.js LTS&#xf…

海康工业相机SDK二次开发(VS+QT+海康SDK+C++)

前言 工业相机在现代制造和工业自动化中扮演了至关重要的角色,尤其是在高精度、高速度检测中。海康威视工业相机以其性能稳定、图像质量高、兼容性强而受到广泛青睐。特别是搞机器视觉的小伙伴们跟海康打交道肯定不在少数,笔者在平常项目中跟海康相关人…

深度学习|pytorch基本运算-乘除法和幂运算

【1】引言 前序学习进程中,已经对pytorch张量数据的生成和广播做了详细探究,文章链接为: 深度学习|pytorch基本运算-CSDN博客 深度学习|pytorch基本运算-广播失效-CSDN博客 上述探索的内容还止步于张量的加减法,在此基础上&am…

4.2.4 Spark SQL 数据写入模式

在本节实战中,我们详细探讨了Spark SQL中数据写入的四种模式:ErrorIfExists、Append、Overwrite和Ignore。通过具体案例,我们演示了如何使用mode()方法结合SaveMode枚举类来控制数据写入行为。我们首先读取了一个JSON文件生成DataFrame&#…

论文笔记: Urban Region Embedding via Multi-View Contrastive Prediction

AAAI 2024 1 INTRO 之前基于多视图的region embedding工作大多遵循相同的模式 单独的单视图表示多视图融合 但这种方法存在明显的局限性:忽略了不同视图之间的信息一致性 一个区域的多个视图所携带的信息是高度相关的,因此它们的表示应该是一致的如果能…

初学者如何微调大模型?从0到1详解

本文将手把手带你从0到1,详细解析初学者如何微调大模型,让你也能驾驭这些强大的AI工具。 1. 什么是大模型微调? 想象一下,预训练大模型就像一位博览群书但缺乏专业知识的通才。它掌握了海量的通用知识,但可能无法完美…

西瓜书第十一章——降维与度量学习

文章目录 降维与度量学习k近邻学习原理头歌实战-numpy实现KNNsklearn实现KNN 降维——多维缩放(Multidimensional Scaling, MDS,MDS)提出背景与原理重述1.**提出背景**2.**数学建模与原理推导**3.**关键推导步骤** Principal Component Analy…

Portainer安装指南:多节点监控的docker管理面板-家庭云计算专家

背景 Portainer 是一个轻量级且功能强大的容器管理面板,专为 Docker 和 Kubernetes 环境设计。它通过直观的 Web 界面简化了容器的部署、管理和监控,即使是非技术用户也能轻松上手。Portainer 支持多节点管理,允许用户从一个中央控制台管理多…

vscode实用配置

前端开发安装插件: 1.可以更好看的显示文件图标 2.用户快速打开文件 使用步骤:在html文件下右键点击 open with live server 即可 刷力扣: 安装这个插件 还需要安装node.js即可

React 项目中封装 Excel 导入导出组件:技术分享与实践

文章目录 前言一、为什么需要封装 Excel 组件?二、技术选型三、核心实现1. 安装依赖2. 封装Excel导出3. 封装导入组件 (UploadExcel) 总结 前言 在 React 项目中,处理 Excel 文件的导入和导出是常见的业务需求。无论是导出报表数…

【2025CCF中国开源大会】RISC-V 开源生态的挑战与机遇分论坛重磅来袭!共探开源芯片未来

点击蓝字 关注我们 CCF Opensource Development Committee 开源浪潮正从软件席卷硬件领域,RISC-V作为全球瞩目的开源芯片架构,正在重塑计算生态的版图!相较于成熟的x86与ARM,RISC-V生态虽处爆发初期,却蕴藏着无限可能。…

python完成批量复制Excel文件并根据另一个Excel文件中的名称重命名

import openpyxl import shutil import os # 原始文件路径 original_file "C:/Users/Administrator/Desktop/事业联考面试名单/郑州.xlsx" # 读取包含名称的Excel文件 # 修改为您的文件名 wb openpyxl.load_workbook( "C:/Users/Administrator/Desktop/事…

Vue-2-前端框架Vue基础入门之二

文章目录 1 计算属性1.1 计算属性简介1.2 计算属性示例 2 侦听器2.1 简单的侦听器2.2 深度监听2.3 监听对象单个属性 3 vue-cli3.1 工程化的Vue项目3.2 Vue项目的运行流程 4 vue组件4.1 Vue组件的三个部分4.1.1 template4.1.2 script4.1.3 style 4.2 组件之间的关系4.2.1 使用组…

CPT208 Human-Centric Computing 人机交互 Pt.7 交互和交互界面

文章目录 1. 界面隐喻(Interface metaphors)1.1 界面隐喻的应用方式1.2 界面隐喻的优缺点 2. 交互类型2.1 Instructing(指令式交互)2.2 Conversing(对话式交互)2.3 Manipulating(操作式交互&…

[网页五子棋][匹配模块]前后端交互接口(消息推送机制)、客户端开发(匹配页面、匹配功能)

让多个用户,在游戏大厅中能够进行匹配,系统会把实力相近的两个玩家凑成一桌,进行对战 约定前后端交互接口 消息推送机制 匹配这样的功能,也是依赖消息推送机制的 玩家 1 点击开始匹配按钮,就会告诉服务器&#xff1…

【数据分析】Matplotlib+Pandas+Seaborn绘图

【数据分析】MatplotlibPandasSeaborn绘图 (一)Matplotlib绘图1.1 matplotlib绘图方式1: 状态接口1.2 matplotlib绘图方式2: 面向对象1.3 通过安斯科姆数据集, 说明可视化的重要性1.4 MatPlotlib绘图-单变量-直方图1.5 MatPlotlib绘图-双变量-散点图1.6 …

NLP学习路线图(十五):TF-IDF(词频-逆文档频率)

在自然语言处理(NLP)的浩瀚宇宙中,TF-IDF(词频-逆文档频率) 犹如一颗恒星,虽古老却依然璀璨。当ChatGPT、BERT等大模型光芒四射时,TF-IDF作为传统方法的代表,其简洁性、高效性与可解…

[Redis] Redis命令在Pycharm中的使用

初次学习,如有错误还请指正 目录 String命令 Hash命令 List命令 set命令 SortedSet命令 连接pycharm的过程见:[Redis] 在Linux中安装Redis并连接桌面客户端或Pycharm-CSDN博客 redis命令的使用见:[Redis] Redis命令(1&#xf…

openpnp - 给M4x0.7mm的直油嘴加油的工具选择

文章目录 openpnp - 给M4x0.7mm的直油嘴加油的工具选择概述如果换上带卡口的M4x0.7直油嘴END openpnp - 给M4x0.7mm的直油嘴加油的工具选择 概述 X导轨用了一个HG15的滑块 滑块上的注油口的黄油嘴是M4x0.7mm的直油嘴。 外表面是6边形的柱子,没有可以卡住加油嘴工…

EasyExcel复杂Excel导出

效果图展示 1、引入依赖 <!-- easyExcel --> <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.2</version> </dependency>2、实体类 import com.alibaba.excel.annotatio…