【go寫設計模式】單例模式--全都用我的
阿新 • • 發佈:2022-05-18
單例模式
問題
為什麼要有單例模式?
第一是不想浪費資源,多次初始化會造成浪費。都用我的就好了。
其次是統一,如果是需要統一的東西,那就只創立一個入口,讓大家只能用我的。
使用場景
- 需要頻繁建立的一些類,使用單例可以降低系統的記憶體壓力,減少 GC。
- 某類只要求生成一個物件的時候,如一個班中的班長、每個人的身份證號等。
- 某些類建立例項時佔用資源較多,或例項化耗時較長,且經常使用。
- 某類需要頻繁例項化,而建立的物件又頻繁被銷燬的時候,如多執行緒的執行緒池、網路連線池等。
- 頻繁訪問資料庫或檔案的物件。
- 對於一些控制硬體級別的操作,或者從系統上來講應當是單一控制邏輯的操作,如果有多個例項,則系統會完全亂套。
- 當物件需要被共享的場合。由於單例模式只允許建立一個物件,共享該物件可以節省記憶體,並加快物件訪問速度。如 Web 中的配置物件、資料庫的連線池等。
實現
懶漢式:在使用的時候再初始化。針對要強制統一的情況。
餓漢式:最開始就初始化。針對不想浪費資源的情況,是大量使用的類。
程式碼
//Singleton 懶漢式單例 type Singleton struct{} var singleton *Singleton var once sync.Once //GetInstance 用於獲取單例模式物件 func GetInstance() *Singleton { once.Do(func() { singleton = &Singleton{} }) return singleton } // Singleton2 餓漢式單例 type Singleton2 struct{} var singleton2 *Singleton2 func init() { singleton2 = &Singleton2{} } // GetInstance 獲取例項 func GetInstance2() *Singleton2 { return singleton2 }
單元測試
package singleton import ( "sync" "testing" ) const parCount = 100 func TestSingleton(t *testing.T) { ins1 := GetInstance() ins2 := GetInstance() if ins1 != ins2 { t.Fatal("instance is not equal") } } func TestParallelSingleton(t *testing.T) { wg := sync.WaitGroup{} wg.Add(parCount) instances := [parCount]*Singleton{} for i := 0; i < parCount; i++ { go func(index int) { instances[index] = GetInstance() wg.Done() }(i) } wg.Wait() for i := 1; i < parCount; i++ { if instances[i] != instances[i-1] { t.Fatal("instance is not equal") } } } func TestSingleton2(t *testing.T) { ins1 := GetInstance2() ins2 := GetInstance2() if ins1 != ins2 { t.Fatal("instance is not equal") } } func TestParallelSingleton2(t *testing.T) { wg := sync.WaitGroup{} wg.Add(parCount) instances := [parCount]*Singleton2{} for i := 0; i < parCount; i++ { go func(index int) { instances[index] = GetInstance2() wg.Done() }(i) } wg.Wait() for i := 1; i < parCount; i++ { if instances[i] != instances[i-1] { t.Fatal("instance is not equal") } } }
單例模式的優點:
- 單例模式可以保證記憶體裡只有一個例項,減少了記憶體的開銷。
- 可以避免對資源的多重佔用。
- 單例模式設定全域性訪問點,可以優化和共享資源的訪問。
單例模式的缺點:
- 單例模式一般沒有介面,擴充套件困難。如果要擴充套件,則除了修改原來的程式碼,沒有第二種途徑,違背開閉原則。
- 在併發測試中,單例模式不利於程式碼除錯。在除錯過程中,如果單例中的程式碼沒有執行完,也不能模擬生成一個新的物件。
- 單例模式的功能程式碼通常寫在一個類中,如果功能設計不合理,則很容易違背單一職責原則。
其實凡是有利就有弊,只要針對自己的場景選擇合適的模式就好了。