Golang常见设计模式如何组合使用_多模式协作设计思路

胖磊大大_5817

胖磊大大_5817

2026-01-25

1022人浏览

原创

Factory 和 Strategy 应在需动态创建算法实例且算法内部依赖可替换行为时组合使用,如支付模块根据 payType 创建不同策略并注入签名器等依赖。

golang常见设计模式如何组合使用_多模式协作设计思路

什么时候该把 Factory 和 Strategy 一起用

当你的业务逻辑需要根据运行时参数动态创建不同算法实现,且这些算法本身又需要封装可替换的行为时,Factory + Strategy 是最自然的组合。比如支付模块:用户选择微信支付或支付宝,系统要创建对应的支付策略实例,而每个策略内部还可能依赖不同的签名生成器、回调处理器。

  • Factory 负责根据 payType 字符串返回具体的 PaymentStrategy 实现
  • Strategy 接口定义 Pay() 和 Refund(),但不关心如何序列化请求或验签
  • 真正解耦的关键在于:Factory 创建 Strategy 时,可以传入其他依赖(比如一个 Signer),而这个 Signer 本身也可以是另一个 Strategy 或由 Builder 构建
type PaymentStrategy interface {
    Pay(order *Order) error
}

type WechatPayStrategy struct {
    signer Signer // 可替换的签名策略
}

func NewWechatPayStrategy(signer Signer) *WechatPayStrategy {
    return &WechatPayStrategy{signer: signer}
}

func PaymentStrategyFactory(payType string) PaymentStrategy {
    switch payType {
    case "wechat":
        return NewWechatPayStrategy(&WechatSHA256Signer{})
    case "alipay":
        return NewAlipayStrategy(&AlipayRSA2Signer{})
    default:
        panic("unknown pay type")
    }
}

为什么 Observer 不该直接嵌套在 Singleton 里

常见错误是把事件监听器注册逻辑塞进单例的 GetInstance() 方法里,导致每次获取实例都重复绑定、内存泄漏、测试困难。Singleton 只应负责“唯一实例”的生命周期;Observer 关系必须可手动管理。

  • 单例对象(如 Logger)暴露 Subscribe() 和 Unsubscribe() 方法,而不是自动绑定
  • 订阅者应在初始化阶段显式调用,比如在 main() 或模块 init() 中完成
  • 若用 sync.Once 初始化单例,切勿在其中调用任何可能阻塞或依赖外部状态的 Observer 注册逻辑
var loggerInstance *Logger
var loggerOnce sync.Once

func GetLogger() *Logger {
    loggerOnce.Do(func() {
        loggerInstance = &Logger{
            subscribers: make(map[int]func(string)),
        }
    })
    return loggerInstance
}

// 正确:由使用者决定何时订阅
func main() {
    log := GetLogger()
    log.Subscribe(1, func(msg string) { fmt.Println("[DEBUG]", msg) })
}

Decorator + Interface 嵌套容易踩的坑

Go 没有继承,靠接口组合实现 Decorator,但过度嵌套会导致方法爆炸和 nil panic。典型场景是给 HTTP handler 加日志、熔断、指标上报——每层 Decorator 都要完整实现 http.Handler 接口,哪怕只改一个方法。

微信公众号文章自动发布助手
微信公众号文章自动发布助手

智能创作与发布:提取公众号文章、生成封面、自动写入草稿箱,适用于标题写稿、参考改写、链接提取和草稿发布的完整流程。

下载
  • 避免让 Decorator 实现整个接口;优先用函数包装器(func(http.Handler) http.Handler)而非结构体
  • 如果必须用结构体 Decorator,确保其字段(如 next http.Handler)在构造时非 nil,并在 ServeHTTP 开头加 if d.next == nil { panic(...) }
  • 多个 Decorator 组合时,顺序敏感:日志 Decorator 包裹熔断 Decorator,和反过来,行为完全不同
func WithMetrics(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 记录指标
        next.ServeHTTP(w, r) // 注意:这里假设 next 不为 nil
    })
}

func main() {
    h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("ok"))
    })
    // 正确顺序:指标 → 熔断 → 日志 → 原始 handler
    http.ListenAndServe(":8080", WithMetrics(WithCircuitBreaker(WithLogging(h))))
}

Builder 在组合模式中不是万能的

Builder 适合构建复杂对象,但一旦和其他模式混用,容易变成“配置黑洞”。比如用 Builder 构建一个带多种 Strategy 的 Service 实例,最后却把所有策略类型、超时、重试次数全塞进 Builder 的链式调用里,导致可读性崩坏。

  • Builder 应只负责“组装”,不负责“决策”;策略选择逻辑(如根据环境变量选重试策略)应放在 Builder 外部
  • Builder 的 Build() 方法不应做 I/O 或阻塞操作(比如读配置文件、连数据库),否则单元测试无法 mock
  • 如果 Builder 返回的对象本身还要被 Decorator 包裹,那 Builder 最好返回接口而非具体类型,否则 Decorator 得知道底层结构

复杂点往往不在模式本身,而在谁持有控制权——是 Builder 决定用哪个 Strategy,还是上层代码传进去。后者更可控,也更容易测试。

golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

539

5

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

616

5

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

1296

5

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.05

811

5

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.05.21

1906

6

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

2025.06.09

5494

18

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

2025.06.10

2554

13

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

2025.06.17

4386

17

golang数组大全
golang数组大全

本专题整合了golang数组相关问题解决方法,想了解更多相关内容,请阅读下面的文章。

2025.06.20

5746

22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go-Zero HTTP服务开发指南
Go-Zero HTTP服务开发指南

共0课时 | 0人学习

Go-Zero goctl安装与使用手册
Go-Zero goctl安装与使用手册

共0课时 | 0人学习

Go-Zero框架快速开始指南
Go-Zero框架快速开始指南

共0课时 | 0人学习