程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

单例模式介绍(单例模式的两种实现方法)

balukai 2025-07-14 14:48:44 文章精选 3 ℃

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式常用于需要全局唯一对象的场景,如配置管理、日志记录、数据库连接池等。

单例模式的特点

  1. 唯一性:确保一个类只有一个实例存在
  2. 全局访问:提供全局访问点,通常通过静态方法实现
  3. 延迟初始化:通常在第一次使用时才创建实例(懒加载)

Go 语言实现单例模式

在 Go 语言中,可以通过以下几种方式实现单例模式:

1. 使用 sync.Once 实现(推荐)

package main

import (
	"fmt"
	"sync"
)

type Logger struct {
}

func (l *Logger) Info(msg string) {
	fmt.Printf(msg)
}

var (
	once   sync.Once
	logger *Logger
)

func GetLogger() Logger {
	once.Do(func() {
		logger = &Logger{}
		fmt.Printf("init logger:\t %p \r\n", logger)
	})
	return *logger
}

func main() {
	for i := 0; i < 10; i++ {
		go func(i int) {
			logger := GetLogger()
			logger.Info(fmt.Sprintf("instance %d,\t %p \r\n", i, &logger))
		}(i)
	}

	fmt.Scanln()
}

2. 使用互斥锁实现(线程安全)

package main

import (
	"fmt"
	"sync"
)

type Singleton struct {
	// 单例属性
}

var (
	instance *Singleton
	mu       sync.Mutex
)

func GetInstance() *Singleton {
	if instance == nil {
		mu.Lock()
		defer mu.Unlock()
		
		// 再次检查,防止在获取锁之前其他goroutine已经创建了实例
		if instance == nil {
			instance = &Singleton{}
			fmt.Println("Creating single instance now.")
		}
	}
	return instance
}

func main() {
	for i := 0; i < 5; i++ {
		go GetInstance()
	}
	fmt.Scanln()
}

3. 包级变量实现(最简单,但不支持延迟初始化)

package main

import "fmt"

type Singleton struct {
	// 单例属性
}

var instance = &Singleton{}

func GetInstance() *Singleton {
	return instance
}

func main() {
	instance1 := GetInstance()
	instance2 := GetInstance()
	
	if instance1 == instance2 {
		fmt.Println("Both instances are the same.")
	}
}

单例模式的应用场景

  1. 配置管理:全局配置对象只需要一个实例
  2. 日志记录:日志记录器通常只需要一个实例
  3. 数据库连接池:维护一个全局的连接池实例
  4. 缓存系统:全局缓存管理器
  5. 线程池:管理应用程序中的线程资源

注意事项

  1. 并发安全:在多线程/多goroutine环境下,确保单例的创建是线程安全的
  2. 测试困难:单例模式可能使单元测试变得困难,因为它保持了全局状态
  3. 隐藏依赖:单例的使用可能导致代码的依赖关系不明显

在 Go 语言中,推荐使用 sync.Once 来实现单例模式,因为它简洁且高效地解决了并发安全问题。

Tags:

最近发表
标签列表