GoLang设计模式05 - 单例模式
单例模式是什么
单例模式是一种创建型设计模式:单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。
为什么要用单例模式
为什么要用单例模式?在系统中某些对象,我们只需要一个全局的,如果每次实例化会浪费资源。所以单例模式可以节约内存,加快对象访问速度,因此单例模式在某些场合适合使用。比如多个模块使用同一个数据源连接对象;比如配置数据可以由一个单例对象统一读取;还有比如日志文件的对象也可以用单例模式。
单例模式怎么实现
我们可以用一个私有的全局变量来保存一个对象,并且提供一个获取对象的方法,在这个方法里面来实现只创建一次。但是要注意多线程的情况,如果多个线程同时访问,也要保证只创建一个对象。这里我们可以用golang的原子操作来实现。我们这里用sync.Once来实现延迟加载,也就是单例模式中的懒汉模式;还有饿汉模式既是初始化的时候就实例对象
1 package main 2 3 import ( 4 "fmt" 5 "sync" 6 "sync/atomic" 7 ) 8 9 type Singleton struct { 10 } 11 12 //饿汉,最优雅,强烈推荐 13 var instance0 *Singleton 14 15 func init() { 16 instance0 = new(Singleton) 17 } 18 func GetInstanceHungry() *Singleton { 19 return instance0 20 } 21 22 //懒汉1,使用sync.Once包 23 var instance1 *Singleton 24 var once sync.Once 25 26 func GetInstanceLazy() *Singleton { 27 once.Do(func() { 28 instance1 = new(Singleton) 29 }) 30 return instance1 31 } 32 33 //懒汉2,自己解决并发问题,使用sync/atomic包、sync.Mutex包 34 var instance2 *Singleton 35 var lock = new(sync.Mutex) 36 37 var flag int32 38 39 func GetInstanceLazy2() *Singleton { 40 if atomic.LoadInt32(&flag) == 1 { 41 return instance2 42 } 43 if instance2 == nil { 44 lock.Lock() 45 defer lock.Unlock() 46 instance2 = new(Singleton) 47 atomic.StoreInt32(&flag, 1) 48 } 49 return instance2 50 } 51 52 func main() { 53 if GetInstanceLazy2() == GetInstanceLazy2() { 54 fmt.Println("is equal") 55 } else { 56 fmt.Println("not equal") 57 } 58 if GetInstanceLazy() == GetInstanceLazy() { 59 fmt.Println("is equal") 60 } else { 61 fmt.Println("not equal") 62 } 63 if GetInstanceHungry() == GetInstanceHungry() { 64 fmt.Println("is equal") 65 } else { 66 fmt.Println("not equal") 67 } 68 }
优点
- 为整个系统提供一个全局的访问点,利于管理。
- 全局只有一个该对象,节约内存。
- 避免了频繁的创建销毁,提示性能。
缺点
- 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误。
- 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
浙公网安备 33010602011771号