单例模式-go语言实现

一、理论知识

单例设计模式(Singleton Design Pattern)是指一个对象只允许被实例化一次,并提供一个访问该实例的全局访问点。

应用场景:

  1. 避免资源访问冲突,例如写日志文件操作;
  2. 表示业务概念上的全局唯一类,例如ID生成器、配置信息、连接池类等;

优点:

  • 减少了内存开销,尤其是频繁地创建和销毁实例时
  • 避免对资源的重复占用,例如文件操作

缺点:

  • 对OOP特性不友好
    • 以id生成器为例,如果采用了单例模式,就违背了基于接口而非实现的设计原则,也就违背了广义上的抽象特性,如果某一天需要替换id生成器时,成本很大。
  • 单例会隐藏类之间的依赖关系
    • 单例类不需要显示创建、不需要依赖参数传递,如果代码关系复杂时,调用关系会被隐藏得很隐蔽。
  • 单例对代码拓展性不友好
    • 单例模式模式只能有一个对象实例,如果某一天需要在代码中创建两个或多个实例,改动代价就特别大。例如如果采用了单例连接池,后续需要改造成两个连接池,一个普通sql、一个慢sql。

二、代码实现

package a_singleton

import "sync"

type Singleton struct{}

var ins *Singleton

// GetInstanceLazy 懒汉式。非并发安全。
func GetInstanceLazy() *Singleton {
	if ins == nil {
		ins = &Singleton{}
	}
	return ins
}

// GetInstanceLazyWithLock 懒汉式加锁,并发安全,但是性能差
var mu sync.Mutex
func GetInstanceLazyWithLock() *Singleton {
	mu.Lock()
	defer mu.Unlock()

	if ins == nil {
		ins = &Singleton{}
	}
	return ins
}

// GetInstanceLazyWithDoubleCheck 懒汉式-双重检查。并发安全,性能ok。
// Java版该实现存在CPU指令重排序问题,需要volatile关键字禁止指令重排序
func GetInstanceLazyWithDoubleCheck() *Singleton {
	if ins == nil {
		mu.Lock()
		defer mu.Unlock()

		if ins == nil {
			ins = &Singleton{}
		}
	}
	return ins
}

// GetInstanceHungry 饿汉式
var insHungry *Singleton = &Singleton{}
func GetInstanceHungry() *Singleton {
	return insHungry
}

// GetInstanceOnce 利用go自带并发工具sync.Once
var once sync.Once
func GetInstanceOnce() *Singleton {
	once.Do(func() {
		ins = &Singleton{}
	})
	return ins
}
posted @ 2023-02-05 22:46  🐫沙漠骆驼  阅读(74)  评论(0)    收藏  举报