[设计模式]创建型模式-单例模式

前言

单例模式是最简单的一种模式。在Go中,单例模式指的是全局只有一个实例,并且它负责创建自己的对象。单例模式有减少内存和系统资源开销、防止多个实例产生冲突等优点。

因为单例模式保证了实例的全局唯一性,并且只被初始化一次,所以比较适合全局共享一个实例,且只需要被初始化一次的场景,例如数据库实例、全局配置、全局任务池等。

单例模式又分为饿汉方式和懒汉方式。饿汉方式是指全局的单例实例在包被加载时创建,而懒汉方式指全局的单例实例在第一次被使用时创建。其中懒汉方式是开源项目中使用最多的方式。

示例代码

Go

懒汉方式的缺点是非并发安全,实际使用中一般加锁,或者使用sync.Once

复制代码
package singleton  
  
import "sync"  
  
type Singleton interface {  
    foo()  
}  
  
type singleton struct{}  
  
func (s singleton) foo() {}  
  
var (  
    instance *singleton  
    once     sync.Once  
)  
  
func GetInstance() Singleton {  
    once.Do(func() {  
       instance = &singleton{}  
    })  
  
    return instance  
}

单元测试

复制代码
package singleton  
  
import (  
    "sync"  
    "testing")  
  
const parCount = 100  
  
func TestSingleton(t *testing.T) {  
    ins1 := GetInstance()  
    ins2 := GetInstance()  
    if ins1 != ins2 {  
       t.Fatal("instance is not equal")  
    }  
}  
  
func TestParallelSingleton(t *testing.T) {  
    start := make(chan struct{})  
    wg := sync.WaitGroup{}  
    wg.Add(parCount)  
  
    instance := [parCount]Singleton{}  
    for i := 0; i < parCount; i++ {  
       go func(index int) {  
          <-start  
          instance[index] = GetInstance()  
          wg.Done()  
       }(i)  
    }  
    close(start)  
    wg.Wait()  
    for i := 1; i < parCount; i++ {  
       if instance[i] != instance[i-1] {  
          t.Fatal("instance is not equal")  
       }  
    }  
}

Python

python的包是天然的单例模式,只要放到单独的包中,import时就是引用的单例。

如果要在一个包内使用设计模式,也有以下几种方式。

使用函数装饰器实现单例
复制代码
def singleton(cls):  
    _instance = {}  
  
    def inner():  
        if cls not in _instance:  
            _instance[cls] = cls()  
        return _instance[cls]  
  
    return inner  
  
  
@singleton  
class MyCls:  
    def __init__(self):  
        pass  
  
  
if __name__ == "__main__":  
    a = MyCls()  
    b = MyCls()  
    print(id(a) == id(b))  # 输出结果应为 True
使用类装饰器实现单例
复制代码
class Singleton:  
    def __init__(self, cls):  
        self._cls = cls  
        self._instance = {}  
  
    def __call__(self):  
        if self._cls not in self._instance:  
            self._instance[self._cls] = self._cls()  
        return self._instance[self._cls]  
  
  
@Singleton  
class MyCls:  
    def __init__(self):  
        pass  
  
  
if __name__ == "__main__":  
    a = MyCls()  
    b = MyCls()  
    print(id(a) == id(b))  # 输出结果应该是True
相关推荐
dialect_3 小时前
KMP算法
开发语言·c++·算法
总要学点什么3 小时前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
开开心心_Every5 小时前
快速隐藏程序工具自定义快捷键一键切换
java·开发语言·前端·spring·智能手机·word·intellij-idea
chenbingjie_c5 小时前
C++ 多态完全指南:从虚函数重写到虚函数表原理
开发语言·c++
吴卫斌5 小时前
定投ETF实战指南(四):行业/主题ETF——定投的“进攻端“
开发语言·python·股票·量化
超级架构师6 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
叼烟扛炮7 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
LMT流氓兔8 小时前
第五单元——第十六课:给书店助手加上网页界面
java·开发语言·jvm·人工智能·oracle·langchain·1024程序员节
专注仿真8 小时前
梯度提升类(XFBoost)算法详解与代码实例
开发语言·人工智能·python·算法·大模型训练·控制算法
外收内放8 小时前
Python基础语法练习题(75)
开发语言·python·学习