创建型-单例模式(Singleton Implementation)
单例模式是一种创建型设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点以访问该实例。
现实生活中的例子:
同一时间只能有一个国家的总统。 无论何时打电话,都必须将同一位总统付诸行动。 这里的总统就是单例。
通俗解释:
确保只有特定类的一个对象被创建。
维基百科:
在软件工程中,单例模式是一种软件设计模式,它将类的实例化限制为一个对象。当仅需要一个对象来协调整个系统的操作时,这非常有用。
这在某些情况下非常有用,例如控制共享资源、管理配置信息、日志记录等。单例模式通常涉及以下几个要素:
- 私有构造函数(Private Constructor):确保其他类无法直接实例化该类,只能通过特定的方法获取实例。
- 私有静态成员变量(Private Static Member):用于保存唯一实例。
- 公有静态方法(Public Static Method):提供对唯一实例的访问。这是获取单例实例的唯一途径。
下面是一个使用 Go 语言实现的单例模式示例:
package main
import (
"fmt"
"sync"
)
type Singleton struct {
}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
fmt.Println("once") //无论这个GetInstance执行多少次 这个once只会执行一次
instance = &Singleton{}
})
return instance
}
func main() {
a1 := GetInstance()
a2 := GetInstance()
fmt.Println(*a1 == *a2) // true
}
在这个示例中,GetInstance
函数利用了 sync.Once
来保证只有一个实例会被创建。第一次调用 GetInstance
时,sync.Once
会执行其中的代码块,并将 instance
初始化为新的 Singleton
实例。之后的调用将直接返回之前创建的实例。
sync.Once
是 Go 语言标准库中提供的一种线程安全的机制。它可以确保其中的代码块只会在第一次调用时执行一次,之后的调用都会被忽略,从而保证了只有一个线程能够执行其中的代码。
在多线程环境中,sync.Once
使用了内部的锁和原子操作来实现,以确保在多个线程同时尝试执行代码块时,只有一个线程能够成功执行,其他线程会被阻塞。这使得 sync.Once
在实现单例模式等场景时非常有用,能够确保只有一个实例被创建。
使用单例模式时要注意以下几点:
- 线程安全性:在多线程环境中,要确保单例模式的实现是线程安全的,以防止并发访问导致的问题。
- 懒加载:有时候可能希望单例实例在需要的时候再被创建,这样可以避免不必要的资源消耗。
- 全局状态:单例模式引入了全局状态,这可能会增加代码的复杂性和耦合性。谨慎使用单例,确保它适合你的设计。
- 测试难度:由于单例模式引入了全局状态,可能会增加单元测试的难度。可以使用依赖注入等技术来缓解这个问题。
饿汉式(Eager Initialization)是单例模式的另一种实现方式
它在类加载的时候就创建了实例,无论是否被使用。
这样可以保证在任何时候都只有一个实例存在。以下是使用 Go 语言实现饿汉式单例模式的示例:
package singleton
type Singleton struct {
// 你的单例结构体字段
}
var instance = &Singleton{} // 在包加载时就创建实例
func GetInstance() *Singleton {
return instance
}
自己手动互斥锁来实现懒汉式单例模式
package singleton
import (
"sync"
)
type Singleton struct {
// 你的单例结构体字段
}
var instance *Singleton
var mu sync.Mutex
func GetInstance() *Singleton {
if instance == nil {
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &Singleton{}
}
}
return instance
}
在这个示例中,GetInstance
函数使用了互斥锁 sync.Mutex
来确保在多线程环境中只有一个线程可以创建实例。当第一个线程进入函数时,它会获取锁并创建实例,之后的线程会等待直到锁被释放。这样可以避免在并发情况下出现多个实例的问题。
评论区