之前在作java的時候,常常會用到設計模式,如單例模式、工廠模式、觀察者模式等。其實設計模式和語言無關,先簡單回顧下單例模式吧,單例模式是一種用在特定場景的設計模式。好比,讀取程序的配置文件的時候就會用到單例模式。java
想象一下,假若有個類的實例是來對配置文件進行操做,若是不用單例模式,系統中任何用到讀取配置文件的地方都將會建立一個對象,這得多麼浪費內存。golang
實際上改對象只須要被實例化一次便可。單例模式的抽象表達就是:在程序中咱們只須要某個類實例化一次便可,保證一個類僅有一個實例,並提供一個獲取實例的方法。設計模式
單例模式有懶漢式和餓漢式。在用Go實現以前,先看看Java的實現。
在java中無論是懶漢式仍是餓漢式都會將構造方法私有化。這點不用解釋,由於不須要經過外部來實例化對象,把建立對象的權限封鎖。安全
所謂懶漢式,也就是在建立對象時比較懶嘛,先不着急建立對象,在須要的時候才建立對象。這裏看下java的實現,暫不考慮併發問題,併發加上synchronized便可。併發
1 public class Singleton { 2 private static Singleton single = null; 3 private Singleton(){ 4 } 5 public static Singleton getSingle() { 6 if (single == null) { 7 single = new Singleton(); 8 } 9 return single; 10 } 11}
那麼上面的設計模式可否用Go語言實現呢?答案是確定的。Go語言沒有private這樣的權限控制,很簡單的是經過首字母大小寫來控制外部是否可以訪問。函數
1 type config struct { 2 } 3 4 var cfg *config 5 func getInstane() *config { 6 if cfg == nil { 7 cfg = new(Config) 8 return cfg 9 } 10 return cfg 11}
上面沒有考慮線程安全,咱們能夠本身加鎖保證安全,也能夠用Golang 中的sync.Once結構體,該結構體提供了一個Do方法,Do函數裏面的函數只有在第一次纔會被調用,該方法只會生成一個實例,且也是線程安全的。線程
1 type config struct { 2 } 3 4 var cfg *config 5 var oSingle sync.Once 6 7 func getInstane() *config { 8 oSingle.Do( 9 func() { 10 cfg = new(config) 11 }) 12 return cfg 13 }
餓漢模式和懶漢模式不一樣的只是在提供獲取實例的方法上。仍是先來看下java的餓漢模式:設計
1 public class Singleton { 2 private static Singleton single = new Singleton();// 只會建立一次實例 3 private Singleton(){ 4 } 5 public static Singleton getSingle() { 6 return single; // 直接返回 7 }
在go語言中,餓漢模式能夠直接在init函數中初始化或者直接在全局變量中聲明。這區別於java中的變量必須是由static修飾。由於static變量在類加載的時候進行初始化。多個實例會共享這塊內存空間。code
關於爲何能夠直接用全局變量,下回再討論golang中的全局變量。對象
1 type cfg struct { 2 } 3 var cfg *config 4 func init() { 5 cfg = new(config) 6 } 7 // NewConfig 提供獲取實例的方法... 8 func NewConfig() *config { 9 return cfg 10 }
1 type config struct { 2 } 3 var cfg *config = new(config) 4 // NewConfig 提供獲取實例的方法... 5 func NewConfig() *config { 6 return cfg 7 }