1. 程式人生 > 其它 >【go寫設計模式】單例模式--全都用我的

【go寫設計模式】單例模式--全都用我的

單例模式

問題

為什麼要有單例模式?

第一是不想浪費資源,多次初始化會造成浪費。都用我的就好了。
其次是統一,如果是需要統一的東西,那就只創立一個入口,讓大家只能用我的。

使用場景

  • 需要頻繁建立的一些類,使用單例可以降低系統的記憶體壓力,減少 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")
		}
	}
}

單例模式的優點:

  • 單例模式可以保證記憶體裡只有一個例項,減少了記憶體的開銷。
  • 可以避免對資源的多重佔用。
  • 單例模式設定全域性訪問點,可以優化和共享資源的訪問。

單例模式的缺點:

  • 單例模式一般沒有介面,擴充套件困難。如果要擴充套件,則除了修改原來的程式碼,沒有第二種途徑,違背開閉原則。
  • 在併發測試中,單例模式不利於程式碼除錯。在除錯過程中,如果單例中的程式碼沒有執行完,也不能模擬生成一個新的物件。
  • 單例模式的功能程式碼通常寫在一個類中,如果功能設計不合理,則很容易違背單一職責原則。

其實凡是有利就有弊,只要針對自己的場景選擇合適的模式就好了。