乐趣区

关于go: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()}

简略工厂模式

退出移动版