Go设计模式之单例模式讲解和代码示例

 更新时间:2023年07月26日 08:18:32   作者:demo007x  
单例是一种创建型设计模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点,本文就通过代码示例给大家讲讲Go单例模式,需要的朋友可以参考下

Go 单例模式讲解和代码示例.

单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。

单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。

在某些其他上下文中, 你不能使用依赖于单例的类。 你也将必须使用单例类。 绝大多数情况下, 该限制会在创建单元测试时出现。

概念示例

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

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

一些值得注意的地方:

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

single.go: 单例

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
}

main.go: 客户端代码

package main
import (
    "fmt"
)
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()
}

output.txt: 执行结果

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.

另一个例子

  • init函数

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

  • sync.Once

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

syncOnce.go: 单例

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
}

main.go: 客户端代码

package main
import (
    "fmt"
)
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()
}

output.txt: 执行结果

Creating single instance now.
Single instance already created.
Single instance already created.

到此这篇关于Go设计模式之单例模式讲解和代码示例的文章就介绍到这了,更多相关Go单例模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang使用redis实现全文搜索功能详解

    golang使用redis实现全文搜索功能详解

    这篇文章主要为大家详细介绍了golang如何使用redis实现全文搜索功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-02-02
  • Golang等多种语言转数组成字符串举例详解

    Golang等多种语言转数组成字符串举例详解

    今天写代码遇到数组转换成字符串操作,下面这篇文章主要给大家介绍了关于Golang等多种语言转数组成字符串的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • 使用Go语言实现微信公众平台

    使用Go语言实现微信公众平台

    这篇文章主要介绍了使用Go语言实现微信公众平台,虽然不是全部代码,但是也是给我们提供了一个非常好的思路,需要的朋友可以参考下
    2015-01-01
  • go日志库logrus的安装及快速使用

    go日志库logrus的安装及快速使用

    这篇文章主要为大家介绍了go日志库logrus的安装及快速使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • golang限流库两个大bug(半年之久无人提起)

    golang限流库两个大bug(半年之久无人提起)

    最近我的同事在使用uber-go/ratelimit[1]这个限流库的时候,遇到了两个大 bug,这两个 bug 都是在这个库的最新版本(v0.3.0)中存在的,而这个版本从 7 月初发布都已经过半年了,都没人提 bug,难道大家都没遇到过么
    2023-12-12
  • golang结合mysql设置最大连接数和最大空闲连接数

    golang结合mysql设置最大连接数和最大空闲连接数

    本文介绍golang 中连接MySQL时,如何设置最大连接数和最大空闲连接数,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • Go异步任务解决方案之Asynq库详解

    Go异步任务解决方案之Asynq库详解

    需要在Go应用程序中异步处理任务? Asynq,简单高效的任务队列实现,下面这篇文章主要给大家介绍了关于Go异步任务解决方案之Asynq库的相关资料,需要的朋友可以参考下
    2023-02-02
  • Go语言基础学习之指针详解

    Go语言基础学习之指针详解

    Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。所以本文就来和大家聊聊Go语言中指针的定义与使用,需要的可以参考一下
    2022-12-12
  • go语言规范RESTful API业务错误处理

    go语言规范RESTful API业务错误处理

    这篇文章主要为大家介绍了go语言规范RESTful API业务错误处理方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • golang中byte和rune用法及新手易错点总结

    golang中byte和rune用法及新手易错点总结

    golang内置类型有rune类型和byte类型,下面这篇文章主要给大家介绍了关于golang中byte和rune用法及新手易错点总结的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-03-03

最新评论