单例模式

为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,

1 使用如下的方式,每次都会赋值一份数据,但事实上并没有这个必要,浪费了内存,

type WebConfig struct{
    Port int
}
func GetWebConfig() *WebConfig{
    // 每次都会开辟一块内存,但事实上这个只需要用同一个就可以了
    // 没必要复制多份,
    return &WebConfig{Port: 8080}
}
func main()  {
    c1 := GetWebConfig()
    c2 := GetWebConfig()
    c3 := GetWebConfig()
    fmt.Println(c1==c2, c2==c3)
}
View Code

直接用加锁的方式实现,这个锁加的可以更细,可直接加到if d == nil里面,这称为双重检查,保证线程安全的同时不会影响性能,

var d *WebConfig
var mu sync.Mutex
type WebConfig struct{
    Port int
}
func GetConfig() *WebConfig{
    mu.Lock()
    defer mu.Unlock()
    // d只有为nil的时候才赋值,否则直接返回,这样就实现了只开辟一次空间
    if d == nil{
        d = &WebConfig{Port: 8080}
    }
    return d
}
func main(){
    c1 := GetConfig()
    c2 := GetConfig()
    // c1和c2是同一个,修改了c1,c2也会修改,
    c1.Port = 1111
    fmt.Println(c2, c1 == c2)
}
View Code

用go的内置包实现单例模式更好

var d *WebConfig
var once sync.Once
type WebConfig struct{
    Port int
}
func GetConfig() *WebConfig{
    // 如果有值了就不会加锁,比之前的方法更好,
    once.Do(func() {
        d = &WebConfig{Port: 8080}
    })
    return d
}
func main(){
    c1 := GetConfig()
    c2 := GetConfig()
    // c1和c2是同一个,修改了c1,c2也会修改,
    c1.Port = 1111
    fmt.Println(c2, c1 == c2)
}
View Code

1、饿汉式:在程序启动或单件模式类被加载的时候,单件模式实例就已经被创建。
2、懒汉式:当程序第一次访问单件模式实例时才进行创建。上面就是懒汉式,
如何选择:如果单件模式实例在系统中经常会被用到,饿汉式是一个不错的选择。
                  反之如果单件模式在系统中会很少用到或者几乎不会用到,那么懒汉式是一个不错的选择。

饿汉式的实现就是直接初始化一个变量,调用函数的时候直接返回,

type WebConfig struct{
    Port int
}
var d = &WebConfig{Port: 8888}
func GetConfig() *WebConfig{
    return d
}
func main(){
    c1 := GetConfig()
    c2 := GetConfig()
    fmt.Println(c2, c1 == c2)
}
View Code

参考:https://www.cnblogs.com/wpnine/p/10426105.html

          https://www.jianshu.com/p/981c4193c871

原文地址:https://www.cnblogs.com/xxswkl/p/14220449.html