單例模式簡介
單例模式是一種設計模式,用於確保一個類只有一個例項,並提供全域性訪問點以獲取該例項。它是一種建立型模式,通常用於需要嚴格控制某個類的例項數量的情況。單例模式確保一個類在整個應用程式生命週期中只有一個例項,因此可以節省系統資源,同時提供了一個集中的訪問點,以便在需要時獲取該例項。
以下是單例模式的關鍵特點:
- 單一例項:單例模式確保一個類只有一個例項物件存在。
- 全域性訪問點:單例模式提供了一個全域性的訪問點,其他物件可以透過該訪問點獲取單例例項。
- 延遲載入(可選):在需要時才進行單例物件的建立,可以減少應用程式啟動時的資源佔用。
- 執行緒安全性(可選):在多執行緒環境下,單例模式需要考慮執行緒安全性,以確保只有一個例項被建立。
單例模式實現
懶漢模式(Lazy Initialization)和餓漢模式(Eager Initialization)是兩種單例模式的實現方式,它們之間的主要區別在於單例物件的初始化時機。
1. 懶漢模式(Lazy Initialization):
- 初始化時機:懶漢模式是延遲載入的,也就是說,單例物件在首次訪問時才進行初始化。在多執行緒環境中,可能會出現競態條件,需要額外的執行緒安全措施來確保只建立一個例項。
- 優點:
- 節省了系統資源,因為在應用程式啟動時不會建立單例物件。
- 可以實現延遲載入,只有在需要時才進行初始化。
- 缺點:
- 在多執行緒環境下,需要考慮執行緒安全性,通常需要使用互斥鎖等機制來保證單例物件的唯一性。
- 首次訪問單例物件時可能會引入額外的效能開銷,因為需要進行初始化。
2. 餓漢模式(Eager Initialization):
- 初始化時機:餓漢模式是在應用程式啟動時就進行單例物件的初始化,無論是否會被使用。因此,單例物件在應用程式生命週期內都存在。
- 優點:
- 不需要考慮多執行緒環境下的執行緒安全性,因為單例物件在應用程式啟動時就已經建立。
- 訪問單例物件時不會引入額外的效能開銷,因為它已經初始化。
- 缺點:
- 可能會浪費系統資源,因為單例物件在應用程式啟動時就被建立,如果一直未被使用,可能會佔用記憶體。
- 不支援延遲載入,因為單例物件在應用程式啟動時就已經初始化。
如何選擇懶漢模式還是餓漢模式:
- 如果應用程式對資源要求敏感,希望儘量減少啟動時的記憶體佔用,或者需要支援延遲載入,可以選擇懶漢模式。
- 如果應用程式對效能要求高,可以接受在應用程式啟動時進行初始化,並且不希望處理多執行緒環境下的執行緒安全問題,可以選擇餓漢模式。
總之,選擇懶漢模式還是餓漢模式應該根據具體的需求和效能要求來決定。無論選擇哪種模式,都需要確保單例物件的唯一性,以及在多執行緒環境下的執行緒安全性。
懶漢模式實現
在 Go 中實現懶漢模式相對簡單,因為 Go 的包系統和併發機制使得這一模式變得非常優雅和安全。下面是一個示例,展示瞭如何在 Go 中建立一個執行緒安全的單例物件:
package singleton
import (
"sync"
)
// Singleton 是一個單例物件的結構體
type Singleton struct {
data int
}
var instance *Singleton
var once sync.Once
// GetInstance 返回 Singleton 的唯一例項
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{} // 只會執行一次
})
return instance
}
// SetData 設定 Singleton 的資料
func (s *Singleton) SetData(data int) {
s.data = data
}
// GetData 獲取 Singleton 的資料
func (s *Singleton) GetData() int {
return s.data
}
在這個示例中,我們建立了一個 Singleton
結構體,它包含一個欄位 data
用於儲存單例物件的資料。我們使用 sync.Once
來確保 GetInstnace
函式只會被執行一次,從而保證單例物件只會被建立一次。
在 main
函式或其他地方,您可以這樣使用這個單例物件:
package main
import (
"fmt"
"singleton"
)
func main() {
instance1 := singleton.GetInstance()
instance1.SetData(42)
instance2 := singleton.GetInstance()
fmt.Println("Instance 1 data:", instance1.GetData())
fmt.Println("Instance 2 data:", instance2.GetData())
if instance1 == instance2 {
fmt.Println("Both instances are the same")
}
}
這個示例中,我們首先透過 GetInstance
函式獲取單例物件 instance1
,然後設定其資料為 42。接著,我們再次獲取單例物件 instance2
,並檢查兩個例項是否相同,從而驗證單例模式的實現。
使用 sync.Once
是 Go 中實現單例模式的推薦方法,因為它既能保證執行緒安全,又能保證懶載入(即只在第一次訪問時建立例項)。這樣可以確保在應用程式中只存在一個例項,並且在需要時進行初始化。
餓漢模式實現
餓漢模式是在應用程式啟動時就進行單例物件的初始化。以下是一個使用餓漢模式的示例:
package singleton
type Singleton struct {
data int
}
var instance = &Singleton{}
func GetInstance() *Singleton {
return instance
}
func (s *Singleton) SetData(data int) {
s.data = data
}
func (s *Singleton) GetData() int {
return s.data
}
在這個示例中,我們在包級別直接建立了一個單例例項 instance
,並在程式啟動時進行初始化。這意味著單例物件在應用程式啟動時就已經存在,而不是在首次訪問時才建立。
宣告:本作品採用署名-非商業性使用-相同方式共享 4.0 國際 (CC BY-NC-SA 4.0)進行許可,使用時請註明出處。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 戀水無意