Go设计模式-单例模式

单例模式

  • 确保任何情况下一个类只有一个实例

通常而言, 单例实例会在结构体首次初始化时创建。 为了实现这一操作, 我们在结构体中定义一个 get­Instance获取实例方法。 该方法将负责创建和返回单例实例。 创建后, 每次调用 get­Instance时都会返回相同的单例实例。

协程方面又有什么需要注意的吗? 每当多个协程想要访问实例时, 单例结构体就必须返回相同的实例。 正因如此, 单例设计模式的实施工作很容易出错。

饿汉模式

在初始阶段创建实例而不是在使用时创建实例。不需要加锁,更安全;但是当程序中不使用该实例会浪费空间,减慢启动速度。

// 使用全局变量
type single struct {

}

var instance = new(single)

func GetInstance()  *single{
    return instance
}

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

}

var instance *single

func init()  {
    instance = new(single)
}

func GetInstance()  *single{
    return instance
}

懒汉模式

sync.Once推荐使用
package main

import (
    "fmt"
    "sync"
)

var once sync.Once

type single struct {
}

var singleInstance *single

func getInstance() *single {
    if singleInstance == nil {
        once.Do(
            func() {
                fmt.Println("Creating single instance now.")
                singleInstance = &single{}
            })
    } else {
        fmt.Println("Single instance already created.")
    }

    return singleInstance
}

func main() {

    for i := 0; i < 30; i++ {
        go getInstance()
    }

    // Scanln is similar to Scan, but stops scanning at a newline and
    // after the final item there must be a newline or EOF.
    fmt.Scanln()
}
双重检测
  • 最开始时会有 nil检查, 确保 sin­gle­Instance单例实例在最开始时为空。 这是为了防止在每次调用 get­Instance方法时都去执行消耗巨大的锁定操作。 如果检查不通过, 则就意味着 sin­gle­Instance字段已被填充。
  • sin­gle­Instance结构体将在锁定期间创建。
  • 在获取到锁后还会有另一个 nil检查。 这是为了确保即便是有多个协程绕过了第一次检查, 也只能有一个可以创建单例实例。 否则, 所有协程都会创建自己的单例结构体实例。
package main

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
}

func main() {

    for i := 0; i < 30; i++ {
        go getInstance()
    }

    // Scanln is similar to Scan, but stops scanning at a newline and
    // after the final item there must be a newline or EOF.
    fmt.Scanln()
}

简单工厂模式

你可能感兴趣的:(go)