创建型设计模式包括:单例模式、工厂模式、建造者模式、原型模式
。它主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。
单例模式用来创建全局唯一的对象。一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。
直接将实例初始化写在init()
方法中,从而在加载包的时候便完成了初始化,且只会初始化一次。
package singleton
// Singleton 饿汉式单例
type Singleton struct{}
var singleton *Singleton
func init() {
singleton = &Singleton{}
}
// GetInstance 获取实例
func GetInstance() *Singleton {
return singleton
}
通过加锁实现只被初始化一次
package singleton
import (
"sync"
)
// Singleton
type Singleton struct{}
var (
singleton *Singleton
mu sync.Mutex
)
// GetInstance 获取实例
func GetInstance() *Singleton {
mu.Lock()
defer mu.Unlock()
if singleton != nil {
singleton = &Singleton{}
}
return singleton
}
上面懒汉式加载用到了锁,但是锁的粒度有点大,每次来获取对象的时候,都会在GetInstance
方法中加锁,影响性能,所以可以使用双重检查的机制
package singleton
import (
"sync"
)
// Singleton
type Singleton struct{}
var (
singleton *Singleton
mu sync.Mutex
)
// GetInstance 获取实例
func GetInstance() *Singleton {
if singleton != nil { // 1
mu.Lock()
defer mu.Unlock()
if singleton != nil { // 2
singleton = &Singleton{}
}
}
return singleton
}
在1
处判断实例不为空的时候,可以直接返回实例了,但如果实例是空的,说明还没有被初始化。在并发情况下,可能有多个协程进入了1
,所以在2
之前,先加锁,只让一个协程进入2
,完成实例初始化,后面进入1
的协程来到2
时,发现实例已经被其他协程初始化过了,可以直接返回实例了。
go
语言中是sync.Once
可以很轻松的保证实例只被初始化一次
package singleTon
import (
"sync"
)
type SingleTon struct {}
var (
once sync.Once
instance *SingleTon
)
func GetInstance() *SingleTon {
once.Do(func() {
instance = &SingleTon{}
})
return instance
}