package main
import (
"fmt"
"sync"
"time"
)
func main() {
// 演示懶漢式
go func() {
s := NewLazySingleton()
s.Say()
}()
singleton := NewLazySingleton()
singleton.Say()
// 演示餓漢式
go func() {
h := NewHungrySingleton()
h.Say()
}()
hungry := NewHungrySingleton()
hungry.Say()
time.Sleep(time.Second)
}
// 定義一個結構體(至關於面嚮對象語言裏面的class)
type Singleton struct {
name string
}
// 至關於class的方法
func (s Singleton) Say() {
fmt.Printf("%s: Say Hello\n", s.name)
}
// 因爲Go並非徹底面向對象的語言,只能經過包級別的全局變量模擬類變量
var lazyInstance *Singleton
// 爲了Go協程併發安全,能夠加鎖,若是不加鎖第一次實例化的時候會出現data race操做,可是其實並不影響功能
// 第一加鎖方式是使用mutex
// mu.lock
// defer mu.unlock
// 可是這樣並不優雅,至關於每次New的時候都得加鎖,影響性能,因此最好的方式是使用once
var once sync.Once
// 懶漢式,所謂懶漢式就是比較懶,等你第一次調用的時候纔會去實例化對象
func NewLazySingleton() *Singleton {
once.Do(func() {
fmt.Println("init lazy")
lazyInstance = &Singleton{name: "lazy"}
})
return lazyInstance
}
var hungryInstance = Singleton{name: "hungry"}
// 餓漢式,所謂餓漢式就是在你調用New以前就已經初始化好了,這個更簡單,並且也不須要鎖
func NewHungrySingleton() *Singleton {
return &hungryInstance
}
複製代碼
單例模式在實際開發中用的仍是比較的多,好比數據庫鏈接池、配置文件等數據庫