Replies: 6 comments 10 replies
-
go 函数选项模式在很多语言中这很容易; 在 C 族语言中, 可以使用不同数量的参数提供相同函数的多个版本; 在像 PHP 这样的语言中, 可以给参数一个默认值,并在调用方法时忽略它们. 但是在 Golang 中, 这两种方式你哪个也用不了. 那么你如何创建一个函数, 用户可以指定一些额外的配置? 示例 var defaultStuffClientOptions = StuffClientOptions{
Retries: 3,
Timeout: 2,
}
type StuffClientOption func(*StuffClientOptions)
type StuffClientOptions struct {
Retries int //number of times to retry the request before giving up
Timeout int //connection timeout in seconds
}
func WithRetries(r int) StuffClientOption {
return func(o *StuffClientOptions) {
o.Retries = r
}
}
func WithTimeout(t int) StuffClientOption {
return func(o *StuffClientOptions) {
o.Timeout = t
}
}
type StuffClient interface {
DoStuff() error
}
type stuffClient struct {
conn Connection
timeout int
retries int
}
type Connection struct {}
func NewStuffClient(conn Connection, opts ...StuffClientOption) StuffClient {
options := defaultStuffClientOptions
for _, o := range opts {
o(&options)
}
return &stuffClient{
conn: conn,
timeout: options.Timeout,
retries: options.Retries,
}
}
func (c stuffClient) DoStuff() error {
return nil
} |
Beta Was this translation helpful? Give feedback.
-
Go语言实现23种设计模式
|
||||||||||||||||||||||||||||||||||||||||||||||||
Beta Was this translation helpful? Give feedback.
-
Refactoring.Guru欢迎来到 Refactoring.Guru。 在这里, 您可以免费在线学习代码重构、 设计模式、 SOLID 原则 (单一职责、 开闭原则、 里氏替换、 接口隔离以及依赖反转) 以及其他和智能编程主题相关的一切内容。 |
Beta Was this translation helpful? Give feedback.
-
图说设计模式 |
Beta Was this translation helpful? Give feedback.
-
UML®
|
Beta Was this translation helpful? Give feedback.
-
动态配置反序列化工厂模式📝 设计模式总结🎯 模式名称"配置类型工厂模式" 或 "动态配置反序列化模式" 📖 模式描述这是一种处理多类型配置反序列化的常用模式,特别适用于:
🏗️ 核心思想
💡 设计优点
🔧 参考伪代码模板1. 基础结构定义// 统一配置接口
type Config interface {
Validate() error
Create() (SomeInterface, error)
}
// 配置集合 - 支持多种类型
type Configs map[string]Config
// 工厂函数类型
type ConfigFactory func() Config2. 工厂注册表// 工厂注册表 - 核心设计
var configFactories = map[string]ConfigFactory{
"type1": func() Config { return new(Type1Config) },
"type2": func() Config { return new(Type2Config) },
"type3": func() Config { return new(Type3Config) },
}
// 注册新类型 - 扩展点
func RegisterConfigType(name string, factory ConfigFactory) {
configFactories[name] = factory
}3. 自定义反序列化// Configs 的自定义 JSON 反序列化
func (c Configs) UnmarshalJSON(data []byte) error {
// 解析为原始 map
var raw map[string]json.RawMessage
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
// 为每种类型创建具体实例
for typeName, typeData := range raw {
factory, exists := configFactories[typeName]
if !exists {
return fmt.Errorf("unknown config type: %s", typeName)
}
// 创建具体类型实例
config := factory()
// 反序列化到具体类型
if err := json.Unmarshal(typeData, config); err != nil {
return fmt.Errorf("decode %s: %w", typeName, err)
}
c[typeName] = config
}
return nil
}4. Viper 解码钩子// Viper 解码钩子函数 - 关键设计
func ConfigsDecodeHook(from reflect.Value, to reflect.Value) (interface{}, error) {
// 检查目标类型是否为 Configs
if to.Type() != reflect.TypeOf(Configs{}) {
return from.Interface(), nil // 不是目标类型,原样返回
}
// 转换为 JSON 再反序列化 - 技巧性处理
jsonData, err := json.Marshal(from.Interface())
if err != nil {
return nil, fmt.Errorf("marshal to json: %w", err)
}
var configs Configs
if err := json.Unmarshal(jsonData, &configs); err != nil {
return nil, fmt.Errorf("unmarshal from json: %w", err)
}
return configs, nil
}5. 具体配置类型实现// 具体配置类型 1
type Type1Config struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
func (c *Type1Config) Validate() error {
if c.Field1 == "" {
return fmt.Errorf("field1 is required")
}
return nil
}
func (c *Type1Config) Create() (SomeInterface, error) {
// 创建具体实现
return NewType1Impl(c.Field1, c.Field2), nil
}
// 具体配置类型 2
type Type2Config struct {
URL string `json:"url"`
Timeout Duration `json:"timeout"`
Backends []string `json:"backends"`
}
func (c *Type2Config) Validate() error {
if c.URL == "" {
return fmt.Errorf("url is required")
}
if len(c.Backends) == 0 {
return fmt.Errorf("at least one backend required")
}
return nil
}
func (c *Type2Config) Create() (SomeInterface, error) {
return NewType2Impl(c.URL, c.Timeout, c.Backends), nil
}6. 使用示例// 配置结构体
type AppConfig struct {
Server ServerConfig `json:"server" mapstructure:"server"`
Auth Configs `json:"auth" mapstructure:"auth"` // 关键字段
Logger log.Options `json:"logger" mapstructure:"logger"`
}
// 配置文件示例 (YAML)
auth:
database:
url: "postgres://localhost:5432/mydb"
maxConnections: 100
timeout: "30s"
cache:
type: "redis"
addr: "localhost:6379"
password: ""
db: 0
// 加载配置
func loadConfig() (*AppConfig, error) {
var config AppConfig
// 关键:使用自定义解码钩子
err := viper.Unmarshal(&config, viper.DecodeHook(ConfigsDecodeHook))
if err != nil {
return nil, fmt.Errorf("unmarshal config: %w", err)
}
return &config, nil
}
// 使用配置
func main() {
config, err := loadConfig()
if err != nil {
log.Fatal(err)
}
// 遍历所有认证配置
for authType, authConfig := range config.Auth {
fmt.Printf("Auth Type: %s\n", authType)
// 验证配置
if err := authConfig.Validate(); err != nil {
log.Printf("Invalid config for %s: %v", authType, err)
continue
}
// 创建认证实例
authenticator, err := authConfig.Create()
if err != nil {
log.Printf("Failed to create authenticator for %s: %v", authType, err)
continue
}
// 使用 authenticator...
fmt.Printf("Created authenticator: %T\n", authenticator)
}
}📋 使用场景总结✅ 适用场景
❌ 不适用场景
🎯 关键要点记忆
🔍 实际应用示例这种模式在以下开源项目中广泛应用:
这个模式在 Go 项目中非常实用,特别是构建可扩展的配置系统时!通过这种模式,可以轻松支持多种后端、插件或服务的动态配置,同时保持代码的整洁和可维护性。 |
Beta Was this translation helpful? Give feedback.






Uh oh!
There was an error while loading. Please reload this page.
-
编程范式
Beta Was this translation helpful? Give feedback.
All reactions