解析option设计模式

解析option设计模式


一、背景

有时候一个函数会有很多参数,为了方便函数的使用,我们会给希望给一些参数设定默认值,调用时只需要传与默认值不同的参数即可。因此选项设计模式顾名思义,就是在构造一个复杂的对象时,能以可选参数(选项)的形式,传入构造对象的函数中,为结构体字段赋值。先直接说下它的应用:

  • 需要构造对象比较复杂,有较多的参数需要赋值
  • 有默认的参数项,然后其余部分的参数需要通过插拔的形式进行配置
  • 以后可能还会有新的参数不断加进来

二、应用demo

现在以一个具体的应用场景来解析下具体怎么构造一个options的设计模式,假如现在业务场景会构造一个配置对象,但是这个配置是有很多默认的配置,只有少部分需要更改。因此可以利用以下的options模式实现对应的业务场景。

go 复制代码
type Config struct {
    param1  string
    param2  string
    option1 string
    option2 string
}

// 声明一个函数类型的变量,用于传参
type Option func(config *Config)

func InitConfig(opts ...Option) *Config {
    config := &Config{
       param1: "default1",
       param2: "default2",
    }
    for _, opt := range opts {
       opt(config)
    }
    return config
}

func WithStringOption1(str string) Option {
    return func(config *Config) {
       config.option1 = str
    }
}

func WithStringOption2(str string) Option {
    return func(config *Config) {
       config.option2 = str
    }
}

func main() {
    config1 := InitConfig(
       WithStringOption1("option1"),
       WithStringOption2("option2"),
    )
    config2 := InitConfig(
       WithStringOption1("option1"),
    )
    fmt.Println(*config1)
    fmt.Println(*config2)
}
  • 代码中param1和param2则是默认配置的参数,option1和option2则是需要进行配置的参数。而最关键的则是通过函数式的变量,将不同的赋值操作统一,最终通过闭包赋值给对应构造对象。
go 复制代码
type Option func(config *Config)

三、Gin中的应用

gin中最典型的应用options模式的就是在构建engine的时候。

  • New(opts ...OptionFunc)
go 复制代码
func New(opts ...OptionFunc) *Engine {
    debugPrintWARNINGNew()
    engine := &Engine{
       RouterGroup: RouterGroup{
          Handlers: nil,
          basePath: "/",
          root:     true,
       },
       FuncMap:                template.FuncMap{},
       RedirectTrailingSlash:  true,
       RedirectFixedPath:      false,
       HandleMethodNotAllowed: false,
       ForwardedByClientIP:    true,
       RemoteIPHeaders:        []string{"X-Forwarded-For", "X-Real-IP"},
       TrustedPlatform:        defaultPlatform,
       UseRawPath:             false,
       RemoveExtraSlash:       false,
       UnescapePathValues:     true,
       MaxMultipartMemory:     defaultMultipartMemory,
       trees:                  make(methodTrees, 0, 9),
       delims:                 render.Delims{Left: "{{", Right: "}}"},
       secureJSONPrefix:       "while(1);",
       trustedProxies:         []string{"0.0.0.0/0", "::/0"},
       trustedCIDRs:           defaultTrustedCIDRs,
    }
    engine.RouterGroup.engine = engine
    engine.pool.New = func() any {
       return engine.allocateContext(engine.maxParams)
    }
    return engine.With(opts...)
}

从代码中可以看出函数中构造了一大堆默认参数,然后在return时返回了engine.With(opts...),继续深入:

go 复制代码
type OptionFunc func(*Engine)

func (engine *Engine) With(opts ...OptionFunc) *Engine {
    for _, opt := range opts {
       opt(engine)
    }

    return engine
}

可以发现这里是通过With函数传入函数式参数实现了options模式。在 golang 的很多开源项目里面也用到了选项模式,比如 grpc 中的 rpc 方法就是采用选项模式设计的,除了必填的 rpc 参数外,还可以一些选项参数,grpc_retry 就是通过这个机制实现的,可以实现自动重试功能。

相关推荐
ly768918 分钟前
Java 设计模式详解:从原则到 23 种经典模式
java·开发语言·设计模式
SoStraw3 小时前
Go + webrpc 实战:人在外面,远程查家里 NAS 磁盘和目录
go·p2p·nas·cgo·json-rpc·webrpc·无公网ip
AI人工智能+电脑小能手3 小时前
大白话说Java设计模式-14-适配器模式(业务实战篇)
java·设计模式·适配器模式·系统兼容·多渠道对接
略略略咯咯11 小时前
(总结)设计模式
设计模式
Cosolar1 天前
DeepSeek Harness 理解 Harness 的设计哲学 - 可组合的插件运行时
人工智能·设计模式·架构
newerp1 天前
Go net/http 标准库基础
后端·程序员·go
2651940511264801 天前
01-整体架构与高可用
go
Nebula_g1 天前
JavaSE基础语法:特殊类(特殊情景下的设计模式)
java·开发语言·设计模式
程序员爱钓鱼1 天前
Go if 判断详解
前端·后端·go
George_Ye2 天前
同一本书,一人一份:我如何设计 AI 个性化扫书报告
设计模式