Go语言中的函数项模式

函数项模式(Functional Options Pattern)是一种创造性的设计模式,允许使用接受零个或多个函数作为参数的可变构造函数来构建复杂结构

在没有函数项模式之前,在包初始化加载配置选项的时候,一般有两种做法

编写不同的构造函数

第一种方法是给每种不同的配置选项编写不同的构造函数

比如有配置项 host、port、maxConn、timeout,把配置项抽象为结构体有:

 type Config struct {host     stringport     intmaxConn  inttimeout  time.Duration}

想要实例化这个结构体,最直接的构造函数为:

 func NewConfig(host string, port, maxConn int, timeout time.Duration) *Config {return &Config{host, port, maxConn, timeout}}

调用 NewConfig 函数后,需要传入 host、port、maxConn、timeout 参数,返回一个指针类型的 Config 对象

但是一般来说,host 和 post 是必填的字段,而 maxConn 和 timeout 应该是可选的,所以构造函数需要考虑是否初始化 maxConn 和 timeout 字段

所需要的构造函数有:

 // 配置 maxConn 和 timeout func NewConfigWithmaxConnAndTimeout(host string, port, maxConn int, timeout time.Duration) *Config {return &Config{host, port, maxConn, timeout}}​// 只配置 maxConnfunc NewConfigWithMaxConn(host string, port, maxConn int) *Config {// timeout 字段默认值为 time.Minutereturn &Config{host, port, maxConn, time.Minute}}​// 只配置 timeoutfunc NewConfigWithTimeout(host string, port int, timeout time.Duration) *Config {// maxConn 字段默认值为 100return &Config{host, port, 100, timeout}}​// maxConn 和 timeout 都使用默认值func NewConfig(host string, port int) *Config {return &Config{host, port, 100, time.Minute}}

对于不同的配置选项编写不同的构造函数,适用于配置较少且变化很少的场景。如果上面的配置项增加一项,那么所有的构造函数都要改一遍,这种方式可伸缩性很差

使用结构体嵌套

第二种方法是使用一个专门用于配置等要求的结构体

当配置项很多的时候,可以创建一个结构体专门存放不同类型的配置选项

比如:

 type AppConfig struct {host     stringport     intmaxConn  inttimeout  time.Duration}​type LogConfig struct {Level    stringFilename stringmaxSize  int}​type Config struct {appConfig AppConfiglogConfig LogConfig}

把配置项按功能拆分,用一个 Config 结构体包含所有的配置选项,这样构造函数可以这样写:

 func NewConfig(appConfig AppConfig, logConfig LogConfig) *Config {return &Config{appConfig, logConfig}}

这种方法有了一定的扩展性,后续有更多的配置选项时,只需要把对应配置项结构体放入 Config 结构体中就可以

但是,要想构造 Config 实例,需要先构造 AppConfig 实例、LogConfig 实例,构造的过程又回到了第一种方法,需要根据不同的配置编写很多的构造函数,而且可伸缩性很差

这种方法适用于配置项很多,变化较少的场景

函数项模式

可以看出来,上面两种方法,扩展性都不是很好,并且不够“优雅”。添加字段会频繁的修改构造函数

使用函数项模式,就可以更灵活的初始化配置选项

使用时,要先定义一个函数类型

 type Option func(*Config)

Option 是一个函数类型,接收一个 *Config 的参数

在设计构造函数的时候,只需要

 func NewConfig(options ...Option) *Config {cfg := &Config{}for _, ops := range options {ops(cfg)}return cfg}

分析一下这个构造函数,它接收一个可变数量的 Option 类型,返回一个 *Config 类型

options 是一个函数类型的切片,存放要对 cfg 做的各种修改,通过遍历 options,对 cfg 实例做各种选项配置,最后返回初始化完成的 Config 实例指针

要想使用这个构造函数,需要先定义各种返回 Option 类型的选项函数

 // 配置 host 和 portfunc WithHostAndPort(host string, port int) Option {return func(cfg *Config) {cfg.host = hostcfg.port = port}}​// 配置 maxConnfunc WithMaxConn(maxConn int) Option {return func(cfg *Config) {cfg.maxConn = maxConn}}​// 配置 timeoutfunc WithTimeout(timeout time.Duration) Option {return func(cfg *Config) {cfg.timeout = timeout}}

构造函数这样使用:

 cfg := NewConfig(WithHostAndPort("localhost", 8088),WithMaxConn(100),WithTaimeout(time.Minute),)

完整示例代码:

 package main​import "time"​// Config 配置结构体type Config struct {host    stringport    intmaxConn inttimeout time.Duration}​// 打印配置项func (cfg Config) print() {println("host:", cfg.host)println("port:", cfg.port)println("maxConn:", cfg.maxConn)println("timeout:", cfg.timeout)}​type Option func(*Config)​func NewConfig(options ...Option) *Config {cfg := &Config{}​for _, ops := range options {ops(cfg)}​return cfg}​// WithHostAndPort 配置 host 和 portfunc WithHostAndPort(host string, port int) Option {return func(cfg *Config) {cfg.host = hostcfg.port = port}}​// WithMaxConn 配置 maxConnfunc WithMaxConn(maxConn int) Option {return func(cfg *Config) {cfg.maxConn = maxConn}}​// WithTimeout 配置 timeoutfunc WithTimeout(timeout time.Duration) Option {return func(cfg *Config) {cfg.timeout = timeout}}​func main() {cfg := NewConfig(WithHostAndPort("localhost", 8088),WithMaxConn(100),WithTimeout(time.Minute),)​cfg.print()/*host: localhostport: 8088maxConn: 100timeout: 60000000000*/}

将来要增加配置选项,只需要增加对应的 WithXXX 选项函数即可,对其他配置项没有任何影响

总结

函数项模式提供了一种更灵活和动态的编码方式,在以下场景可以考虑使用函数项模式:

  • 参数确实比较复杂,影响调用方使用

  • 参数确实有比较清晰明确的默认值

  • 为参数的后续拓展考虑

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

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

相关文章

【微信小程序 事件绑定】

事件绑定 条件渲染 1. block包裹性容器&#xff1a;条件成立渲染 <block wx:if"{{ true }}"><block wx:if"{{true}}"><view>view1</view><view>view2</view> </block>2. wx:if&#xff1a;动态创建移除元素控…

农情监测系统的工作原理

TH-Q3农情监测系统是指利用现代信息技术手段&#xff0c;对农田环境进行实时监测、数据采集、传输和处理&#xff0c;以实现对农田环境的全面感知和智能管理[1]。该系统通过安装各种传感器和监测设备&#xff0c;能够实时监测农田的气象、土壤、植被和其他相关数据&#xff0c;…

VXLAN技术揭秘:实现大规模网络隔离与虚拟机无缝迁移

VXLAN简介 定义 VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;是由RFC定义的一种VLAN扩展方案。VXLAN采用MAC in UDP&#xff08;User Datagram Protocol&#xff09;封装方式&#xff0c;是NVO3&#xff08;Network Virtu…

KOL营销策略:危机公关中的品牌修复与形象重塑

在当今数字化时代&#xff0c;品牌声誉的管理和维护愈发重要。危机公关作为品牌管理的重要一环&#xff0c;对于企业的长期生存和发展具有至关重要的影响。而KOL作为具有强大影响力和号召力的个体&#xff0c;在危机公关中扮演着不可或缺的角色。本文Nox聚星将和大家探讨KOL在危…

男士内裤哪个牌子质量好又舒服?2024男士内裤舒适度排行

男士内裤&#xff0c;不仅仅是一件简单的衣物&#xff0c;更是健康与舒适的关键守护者。作为每位男士的私密伙伴&#xff0c;它承载着每一天的舒适体验与健康保障。因此&#xff0c;选择一款合适的内裤&#xff0c;对男士们来说&#xff0c;显得尤为重要。 我们为您精心总结了…

国标GB28181安防视频监控EasyCVR平台级联时上级平台不显示通道是什么原因?

国标GB28181安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台部署轻快&#xff0c;可支持的主流标准协议有GA/T 1400、国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。 有用户反馈&#xff…

Linux 基本指令1

ls指令 ls【-选项】【目录或文件】当不指定目录或文件时指令能列出当前目录下所有文件除隐藏文件 选项&#xff1a; -a 列出所有包括隐藏的文件-隐藏文件以.开头。 -d 将目录如文件般显示-一般用ls显示目录是显示其目录中所有文件&#xff0c;加-d则显示目录的信息 -r 以反…

22 CRT工具安装流程

22 CRT工具安装流程 SecureCRT 9.5 说明书 SecureCRT 9.5是一款由VanDyke Software开发的终端仿真程序。它为Windows、Mac和Linux操作系统提供了强大的SSH&#xff08;Secure Shell&#xff09;客户端功能。SecureCRT 9.5提供了对Telnet、RLogin、Serial和X.509等协议的支持&…

【安卓设备】通过adb批量安装apk

1、adb链接设备 H:\tv\apk>adb connect 127.0.0.1:21503 2、批量安装apk 如果地址不一致需要将 H:\tv\apk\ 改成自己的路径地址&#xff0c;同时注意该命令只能安装文件名为英文的不支持中文名称&#xff0c;如果有需要先更改文件名称。 H:\tv\apk>for %f in (H:\tv\a…

技术速递|介绍 .NET API 文档的源代码链接

作者&#xff1a;Min Huang&#xff0c;Matt Trilby-Bassett 排版&#xff1a;Alan Wang 开发人员在阅读 API 参考文档时&#xff0c;有时会需要或希望查看相应的源代码。直到不久之前&#xff0c;.NET API 参考文档还没有提供指向源代码的链接&#xff0c;这引起社区添加这一功…

借助ChatGPT撰写学术论文,如何设定有效的角色提示词指

大家好&#xff0c;感谢关注。这个给大家提供关于论文写作方面专业的讲解&#xff0c;以及借助ChatGPT等AI工具如何有效辅助的攻略技巧。有兴趣的朋友可以添加我&#xff08;yida985&#xff09;交流学术写作或ChatGPT等AI领域相关问题&#xff0c;多多交流&#xff0c;相互成就…

12. Django 第三方功能应用

12. 第三方功能应用 因为Django具有很强的可扩展性, 所以延伸了第三方功能应用. 通过本章的学习, 读者能够在网站开发过程中快速实现API接口开发, 验证码生成与使用, 站内搜索引擎, 第三方网站实现用户注册, 异步任务和定时任务, 即时通信等功能.12.1 Django Rest Framework框…

【区块链】记账的千年演化:从泥板到区块链

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 记账的千年演化&#xff1a;从泥板到区块链引言一、古代记账&#xff1a;泥板与…

2024 年勒索软件将比以往更加残酷

如今&#xff0c;世界各地的人们去学校、去医院或去药店时&#xff0c;都会被告知&#xff1a;“抱歉&#xff0c;我们的计算机系统瘫痪了。” 罪魁祸首往往是在世界另一端活动的网络犯罪团伙&#xff0c;他们会要求人们支付系统访问费用或安全归还被盗数据。 尽管警方加大打…

[vue2]深入理解vuex

本节内容 概述初始化仓库定义数据访问数据修改数据处理异步派生数据模块拆分案例-购物车 概述 vuex是一个vue的状态管理工具, 状态就是数据 场景 某个状态在很多个组件使用 (个人信息)多个组件 共同维护 一份数据 (购物车) 优势 数据集中式管理数据响应式变化 初始化仓库 …

Vue36-组件化编程的概念

一、组件化编程VS传统编程 1-1、传统方式的编写应用 存在的问题&#xff1a; 1-2、组件方式的编写应用 注意&#xff1a;是引入&#xff0c;不是复制&#xff01; 体现了封装的概念&#xff01; 二、模块化、组件化

chatgpt: int t[] int *t 区别

在C语言中&#xff0c;int t[]和int *t虽然在某些情况下可以相互替换&#xff0c;但它们有一些关键的区别。这些区别主要体现在声明的语义、内存分配方式和使用场景上。以下是详细的解释&#xff1a; ### 1. int t[] #### 语义: - int t[]声明了一个数组&#xff0c;t是一个数…

Java18新特性总结

Java 18作为Java编程语言的一个重要更新&#xff0c;引入了一系列新特性和改进&#xff0c;旨在提高开发者的生产力和程序的性能。以下是Java 18的主要新特性概述&#xff1a; 元编程功能&#xff1a; Java 18引入了元注释和元类型声明的功能&#xff0c;允许开发人员在编译时…

SonarQube安全扫描常见问题

目录 一、SonarQube质量报告 二、SonarQube扫描常见问题和修复方法 三、SonarQube质量配置 最近小编在使用SonarQube工具进行代码扫描&#xff0c;检查代码异味&#xff0c;系统漏洞等&#xff0c;实际过程中也遇到了不少问题&#xff0c;这篇文章主要列举我遇到的常见问题和…