单例模式

时间:2022-11-17 11:03:08

定义

一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。

单例模式用处

从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。除此之外,我们还可以使用单例解决资源访问冲突的问题。

优缺点

优点:

  • 1、保证一个类只有一个实例。(常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。) 注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。
  • 2、为该实例提供一个全局访问节点。

缺点:

  • 虽然他解决了以上两个问题,但是违反了单一职责原则。

饿汉模式

一些值得注意的地方:

  • 最开始时会有 nil检查, 确保 singleInstance单例实例在最开始时为空。 这是为了防止在每次调用 getInstance方法时都去执行消耗巨大的锁定操作。 如果检查不通过, 则就意味着 singleInstance字段已被填充。
  • singleInstance结构体将在锁定期间创建。
  • 在获取到锁后还会有另一个 nil检查。 这是为了确保即便是有多个协程绕过了第一次检查, 也只能有一个可以创建单例实例。 否则, 所有协程都会创建自 己的单例结构体实例。

代码实现 ​​singular.go​

package singular

import (
"fmt"
"sync"
)

var lock = &sync.Mutex{}

type single struct {
}
var singleInstance *single

func getInstance() *single {
if singleInstance == nil {
lock.Lock()
defer lock.Unlock()
if singleInstance == nil {
fmt.Println("Creating single instance now.")
singleInstance = &single{}
} else {
fmt.Println("Single instance already created.")
}
} else {
fmt.Println("single instance already created.")
}
return singleInstance
}

测试​​singular_test.go​

package singular

import (
"fmt"
"testing"
)

func TestGetSingular(t *testing.T) {
for i := 0; i < 30; i++ {
getInstance()

}
fmt.Scanln()
}

输出

=== RUN   TestGetSingular
Creating single instance now.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
single instance already created.
--- PASS: TestGetSingular (0.00s)
PASS

懒汉模式

第一种

我们可以在 init函数中创建单例实例。 这仅适用于实例的早期初始化工作已经确定时。 init函数仅会在包中的每个文件里调用一次, 所以我们可以确定其只 会创建一个实例。

package lazy

type singleton1 struct {
}

var singleInstance1 *singleton1

func init() {
singleInstance1 = &singleton1{}
}
func GetSingleInstance() *singleton1 {
return &singleton1{}
}

第二种

sync.Once 仅会执行一次操作。 可查看下面的代码

代码实现 ​​lazy.go​

package lazy

import (
"fmt"
"sync"
)

var once sync.Once

type singleton2 struct {
}

var singleInstance2 *singleton2

func getInstance() *singleton2 {
if singleInstance2 == nil {
once.Do(func() {
fmt.Println("creating single instance now.")
singleInstance2 = &singleton2{}
})
} else {
fmt.Println("single instance already create.")
}
return singleInstance2
}

测试 ​​lazy_test.go​

package lazy

import "testing"

func TestGetSingleInstance(t *testing.T) {
for i := 0; i < 20; i++ {
go getInstance()
//go GetSingleInstance()

}
}

输出

=== RUN   TestGetSingleInstance
creating single instance now.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
single instance already create.
--- PASS: TestGetSingleInstance (0.00s)
PASS

原文连接: ​​https://karlhuang95.github.io/​