golang设计模式之单例模式

单例模式

wiki百科: 单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

单例模式要实现的效果就是,对于应用单例模式的类,整个程序中只存在一个实例化对象

go并不是一种面向对象的语言,所以我们使用结构体来替代

有几种方式:

  • 懒汉模式* 饿汉模式* 双重检查锁机制下面拆分讲解:

懒汉模式

1.构建一个示例结构体

 type example struct { 	name string } 

2.设置一个私有变量作为每次要返回的单例

 var instance *example 

3.写一个可以获取单例的方法

 func GetExample() *example {	// 存在线程安全问题,高并发时有可能创建多个对象	if instance == nil {		instance = new(example)	}	return instance} 

4.测试一下func main() { s := GetExample() s.name = "第一次赋值单例模式" fmt.Println(s.name) s2 := GetExample() fmt.Println(s2.name)} 懒汉模式存在线程安全问题,在第3步的时候,如果有多个线程同时调用了这个方法, 那么都会检测到instancenil,就会创建多个对象,所以出现了饿汉模式…

饿汉模式

与懒汉模式类似,不再多说,直接上代码

 // 构建一个结构体,用来实例化单例type example2 struct {	name string}// 声明一个私有变量,作为单例var instance2 *example2// init函数将在包初始化时执行,实例化单例func init() {	instance2 = new(example2)	instance2.name = "初始化单例模式"}func GetInstance2() *example2 {	return instance2}func main() {	s := GetInstance2()	fmt.Println(s.name)} 

饿汉模式将在包加载的时候就创建单例对象,当程序中用不到该对象时,浪费了一部分空间

和懒汉模式相比,更安全,但是会减慢程序启动速度

双重检查机制

懒汉模式存在线程安全问题,一般我们使用互斥锁来解决有可能出现的数据不一致问题

所以修改上面的GetInstance() 方法如下:

 var mux Sync.Mutex func GetInstance() *example { mux.Lock() defer mux.Unlock() if instance == nil { instance = &example{} }return instance } 

如果这样去做,每一次请求单例的时候,都会加锁和减锁,而锁的用处只在于解决对象初始化的时候可能出现的并发问题 当对象被创建之后,加锁就失去了意义,会拖慢速度,所以我们就引入了双重检查机制(Check-lock-Check), 也叫DCL(Double Check Lock), 代码如下:

 func GetInstance() *example {if instance == nil {// 单例没被实例化,才会加锁 mux.Lock()defer mux.Unlock()if instance == nil {// 单例没被实例化才会创建	instance = &example{}}}return instance} 

这样只有当对象未初始化的时候,才会又加锁和减锁的操作

但是又出现了另一个问题:每一次访问都要检查两次,为了解决这个问题,我们可以使用golang标准包中的方法进行原子性操作:

 import "sync" import "sync/atomic"  var initialized uint32  func GetInstance() *example { 	 	// 一次判断即可返回if atomic.LoadUInt32(&initialized) == 1 { 		return instance 	 } mux.Lock() defer mux.Unlock() if initialized == 0 {instance = &example{}atomic.StoreUint32(&initialized, 1) // 原子装载 	} 	return instance } 

以上代码只需要经过一次判断即可返回单例,但是golang标准包中其实给我们提供了相关的方法:

sync.OnceDo方法可以实现在程序运行过程中只运行一次其中的回调,所以最终简化的代码如下:

 type example3 struct {
 	name string
 }
 
 var instance3 *example3
 var once sync.Once
 
 func GetInstance3() *example3 {
 
 	once.Do(func() {
 		instance3 = new(example3)
 		instance3.name = "第一次赋值单例"
 	})
 	return instance3
 }
 
 func main() {
 	e1 := GetInstance3()
 	fmt.Println(e1.name)
 
 	e2 := GetInstance3()
 	fmt.Println(e2.name)
 } 

单例模式是开发中经常用到的设计模式,我在制作自己的web框架 silsuer/bingo 的时候 在环境变量控制、配置项控制等位置都用到了这种模式。

此文章的源码都在这个仓库中: golang设计模式

F%2Fgithub.com%2Fsilsuer%2Fgolang-design-patterns “https://github.com/silsuer/golang-design-patterns”)**

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是几种常见的Golang设计模式: 1. 工厂模式(Factory Pattern):用于创建对象的模式,通过定义一个创建对象的接口来实现对象的实例化。 ```go type Shape interface { Draw() } type Circle struct{} func (c *Circle) Draw() { fmt.Println("Drawing a circle") } type Rectangle struct{} func (r *Rectangle) Draw() { fmt.Println("Drawing a rectangle") } type ShapeFactory struct{} func (sf *ShapeFactory) GetShape(shapeType string) Shape { if shapeType == "circle" { return &Circle{} } else if shapeType == "rectangle" { return &Rectangle{} } return nil } func main() { factory := &ShapeFactory{} circle := factory.GetShape("circle") circle.Draw() // 输出:Drawing a circle rectangle := factory.GetShape("rectangle") rectangle.Draw() // 输出:Drawing a rectangle } ``` 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。 ```go type Singleton struct{} var instance *Singleton func GetInstance() *Singleton { if instance == nil { instance = &Singleton{} } return instance } func main() { singleton1 := GetInstance() singleton2 := GetInstance() fmt.Println(singleton1 == singleton2) // 输出:true } ``` 3. 观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。 ```go type Subject struct { observers []Observer } func (s *Subject) Attach(observer Observer) { s.observers = append(s.observers, observer) } func (s *Subject) Notify() { for _, observer := range s.observers { observer.Update() } } type Observer interface { Update() } type ConcreteObserver struct{} func (co *ConcreteObserver) Update() { fmt.Println("Observer is updated") } func main() { subject := &Subject{} observer := &ConcreteObserver{} subject.Attach(observer) subject.Notify() // 输出:Observer is updated } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值