单例是一种创建型设计模式, 能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
单例拥有与全局变量相同的优缺点。 尽管它们非常有用,但却会破坏代码的模块化特性。
实现方式一
通常而言, 单例实例会在结构体首次初始化时创建。 为了实现这一操作, 我们在结构体中定义一个 getInstance
获取实例方法。 该方法将负责创建和返回单例实例。 创建后,每次调用 getInstance
时都会返回相同的单例实例。
协程方面又有什么需要注意的吗? 每当多个协程想要访问实例时,单例结构体就必须返回相同的实例。 正因如此,单例设计模式的实施工作很容易出错。下方的例子表示了创建单例的正确方式。
一些值得注意的地方:
最开始时会有 nil检查, 确保 singleInstance单例实例在最开始时为空。 这是为了防止在每次调用 getInstance方法时都去执行消耗巨大的锁定操作。 如果检查不通过, 则就意味着 singleInstance字段已被填充。
singleInstance结构体将在锁定期间创建。
在获取到锁后还会有另一个 nil检查。 这是为了确保即便是有多个协程绕过了第一次检查, 也只能有一个可以创建单例实例。 否则, 所有协程都会创建自己的单例结构体实例。
示例代码:
1 | package main |
实现方式二
init
函数
我们可以在init
函数中创建单例实例。 这仅适用于实例的早期初始化工作已经确定时。 init
函数仅会在包中的每个文件里调用一次,所以我们可以确定其只会创建一个实例。sync.Once
sync.Once
仅会执行一次操作。 可查看下面的代码:
1 | package main |