为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,
1 使用如下的方式,每次都会赋值一份数据,但事实上并没有这个必要,浪费了内存,
type WebConfig struct{ Port int } func GetWebConfig() *WebConfig{ // 每次都会开辟一块内存,但事实上这个只需要用同一个就可以了 // 没必要复制多份, return &WebConfig{Port: 8080} } func main() { c1 := GetWebConfig() c2 := GetWebConfig() c3 := GetWebConfig() fmt.Println(c1==c2, c2==c3) }
直接用加锁的方式实现,这个锁加的可以更细,可直接加到if d == nil里面,这称为双重检查,保证线程安全的同时不会影响性能,
var d *WebConfig var mu sync.Mutex type WebConfig struct{ Port int } func GetConfig() *WebConfig{ mu.Lock() defer mu.Unlock() // d只有为nil的时候才赋值,否则直接返回,这样就实现了只开辟一次空间 if d == nil{ d = &WebConfig{Port: 8080} } return d } func main(){ c1 := GetConfig() c2 := GetConfig() // c1和c2是同一个,修改了c1,c2也会修改, c1.Port = 1111 fmt.Println(c2, c1 == c2) }
用go的内置包实现单例模式更好
var d *WebConfig var once sync.Once type WebConfig struct{ Port int } func GetConfig() *WebConfig{ // 如果有值了就不会加锁,比之前的方法更好, once.Do(func() { d = &WebConfig{Port: 8080} }) return d } func main(){ c1 := GetConfig() c2 := GetConfig() // c1和c2是同一个,修改了c1,c2也会修改, c1.Port = 1111 fmt.Println(c2, c1 == c2) }
1、饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。
2、懒汉式:当程序第一次访问单件模式实例时才进行创建。上面就是懒汉式,
如何选择:如果单件模式实例在系统中经常会被用到,饿汉式是一个不错的选择。
反之如果单件模式在系统中会很少用到或者几乎不会用到,那么懒汉式是一个不错的选择。
饿汉式的实现就是直接初始化一个变量,调用函数的时候直接返回,
type WebConfig struct{ Port int } var d = &WebConfig{Port: 8888} func GetConfig() *WebConfig{ return d } func main(){ c1 := GetConfig() c2 := GetConfig() fmt.Println(c2, c1 == c2) }