Golang单例模式和工厂模式详解

我们来详细介绍 Go 语言中的两个经典创建型设计模式单例模式(Singleton Pattern)工厂模式(Factory Pattern)

这两种模式在实际开发中非常常见,尤其是在构建配置管理、数据库连接池、日志系统等场景中。


一、单例模式(Singleton Pattern)

🎯 目的:

确保一个类在整个程序生命周期中只有一个实例,并提供一个全局访问点。

类似于"全局唯一对象",比如:数据库连接池、配置管理器、日志记录器。


✅ Go 实现方式(推荐:sync.Once + 懒加载)

go 复制代码
package main

import (
    "fmt"
    "sync"
)

// ConfigManager 单例结构体
type ConfigManager struct {
    config map[string]string
}

// 全局变量(私有)
var (
    instance *ConfigManager
    once     sync.Once
)

// GetInstance 返回唯一的 ConfigManager 实例
func GetInstance() *ConfigManager {
    once.Do(func() {
        instance = &ConfigManager{
            config: make(map[string]string),
        }
        fmt.Println("ConfigManager 初始化")
    })
    return instance
}

// Set 设置配置
func (c *ConfigManager) Set(key, value string) {
    c.config[key] = value
}

// Get 获取配置
func (c *ConfigManager) Get(key string) string {
    return c.config[key]
}

🔧 使用示例:

go 复制代码
func main() {
    // 获取单例实例
    cfg1 := GetInstance()
    cfg1.Set("host", "localhost")

    // 再次获取,应是同一个实例
    cfg2 := GetInstance()
    fmt.Println(cfg2.Get("host")) // 输出: localhost

    // 验证是否为同一实例
    fmt.Printf("cfg1 == cfg2: %t\n", cfg1 == cfg2) // true
}

✅ 优点:

  • 线程安全(sync.Once 保证只初始化一次)
  • 懒加载(第一次调用才创建)
  • 全局唯一

⚠️ 注意事项:

  • 不要滥用单例(可能导致测试困难、耦合度高)
  • Go 中更推荐依赖注入(DI),但在某些场景下单例仍实用

二、工厂模式(Factory Pattern)

🎯 目的:

定义一个用于创建对象的接口,但让子类决定实例化哪一个类 。Go 中没有"继承",所以通常使用 函数返回接口 来实现。

工厂模式的核心是:解耦对象的创建与使用


1. 简单工厂模式(Simple Factory)

场景:根据类型创建不同的支付方式
go 复制代码
package main

import "fmt"

// Payment 支付接口
type Payment interface {
    Pay(amount float64) string
}

// Alipay 支付宝
type Alipay struct{}

func (a *Alipay) Pay(amount float64) string {
    return fmt.Sprintf("支付宝支付 %.2f 元", amount)
}

// WeChatPay 微信支付
type WeChatPay struct{}

func (w *WeChatPay) Pay(amount float64) string {
    return fmt.Sprintf("微信支付 %.2f 元", amount)
}

// UnionPay 银联支付
type UnionPay struct{}

func (u *UnionPay) Pay(amount float64) string {
    return fmt.Sprintf("银联支付 %.2f 元", amount)
}

// PaymentFactory 工厂函数
func NewPayment(method string) Payment {
    switch method {
    case "alipay":
        return &Alipay{}
    case "wechat":
        return &WeChatPay{}
    case "union":
        return &UnionPay{}
    default:
        panic("不支持的支付方式")
    }
}

🔧 使用示例:

go 复制代码
func main() {
    payment := NewPayment("alipay")
    result := payment.Pay(99.9)
    fmt.Println(result) // 支付宝支付 99.90 元

    payment = NewPayment("wechat")
    result = payment.Pay(50.0)
    fmt.Println(result) // 微信支付 50.00 元
}

✅ 优点:调用方无需知道具体类型,只需传入字符串即可获得对应实现。


2. 抽象工厂模式(Abstract Factory)【可选扩展】

如果需要创建一系列相关或依赖对象(如:主题工厂创建按钮+文本框),可以使用抽象工厂。

go 复制代码
type Button interface {
    Click()
}

type TextBox interface {
    Input(text string)
}

type UIFactory interface {
    CreateButton() Button
    CreateTextBox() TextBox
}

type MacFactory struct{}

func (m *MacFactory) CreateButton() Button { return &MacButton{} }
func (m *MacFactory) CreateTextBox() TextBox { return &MacTextBox{} }

type WinFactory struct{}

func (w *WinFactory) CreateButton() Button { return &WinButton{} }
func (w *WinFactory) CreateTextBox() TextBox { return &WinTextBox{} }

三、单例 vs 工厂模式对比

特性 单例模式 工厂模式
类型 创建型 创建型
目的 确保唯一实例 解耦对象创建过程
核心 全局唯一 多态创建
适用场景 配置管理、连接池 支付系统、插件系统、消息队列选择
Go 实现 sync.Once + 全局变量 函数返回接口
是否线程安全 是(需正确实现) 是(工厂本身无状态)

四、实际应用场景

模式 应用场景
单例模式 - 数据库连接池 - 日志记录器 - 配置中心 - 缓存实例(如全局 Redis 客户端)
工厂模式 - 支付网关选择 - 消息队列驱动(Kafka/RabbitMQ) - 存储后端(本地/云存储) - API 客户端版本切换

五、注意事项(Go 特性)

  1. Go 没有构造函数 :用 NewXXX() 函数代替。
  2. 优先使用接口:工厂返回接口而非具体类型。
  3. 避免全局状态滥用:单例虽方便,但会增加耦合,影响测试。
  4. 推荐依赖注入(DI):比单例更灵活(如使用 Wire、Dig 等框架)。

✅ 总结

🔑 单例模式口诀:

"一生一世一双人 "

全局唯一,懒加载,sync.Once 保安全。

🔑 工厂模式口诀:

"你告诉我类型,我给你对象 "

解耦创建逻辑,扩展无忧。


掌握这两个模式,你就能写出高内聚、低耦合、易扩展的 Go 程序!它们是构建大型系统的基础组件。

相关推荐
promising-w6 分钟前
TYPE-C接口,其实有4种
linux·c语言·开发语言
2501_9160088926 分钟前
JavaScript调试工具有哪些?常见问题与常用调试工具推荐
android·开发语言·javascript·小程序·uni-app·ecmascript·iphone
zero13_小葵司29 分钟前
在不同开发语言与场景下设计模式的使用
java·开发语言·javascript·设计模式·策略模式
烦躁的大鼻嘎32 分钟前
【Linux】深入探索多线程编程:从互斥锁到高性能线程池实战
linux·运维·服务器·开发语言·c++·算法·ubuntu
珹洺44 分钟前
Java-Spring入门指南(十三)SpringMVC基本概念与核心流程详解
java·开发语言·spring
AI+程序员在路上1 小时前
QT6中QGraphicsView功能与应用
开发语言·c++·qt
liuyao_xianhui2 小时前
四数之和_优选算法(C++)双指针法总结
java·开发语言·c++·算法·leetcode·职场和发展
blank@l3 小时前
Python类和对象----实例属性,类属性(这是我理解类和对象最透彻的一次!!)
开发语言·python·python接口自动化基础·python类和对象·python实例属性·python类属性·类属性和实例属性的区别
超奇电子3 小时前
高斯包络调制正弦波的Python代码
开发语言·python
Siren_dream3 小时前
python进阶_Day2
开发语言·python