亦称:Singleton

保证进程中一个类只有一个实例,并提供一个全局访问点。

  • 单例模式能够保证类只有一个实例,即instance
  • 有方法能从外部访问这个实例,即GetInstance()
  • 外部无法创建实例,类的构造方法为私有,外部无法访问

单例模式

使用场景

  • 多线程场景访问资源,控制只有一个对象操作资源,并对该对象加锁使用
  • 需要保证全局唯一的类,如配置类

实现步骤

  1. 在类中添加一个私有静态成员变量用于保存单例实例。
  2. 声明一个公有静态构建方法用于获取单例实例。
  3. 在静态方法中实现"延迟初始化"。该方法会在首次被调用时创建一个新对象,并将其存储在静态成员变量中。此后该方法每次被调用时都返回该实例。
  4. 将类的构造函数设为私有。类的静态方法仍能调用构造函数,但是其他对象不能调用。
  5. 检查客户端代码, 将对单例的构造函数的调用替换为对其静态构建方法的调用。

优缺点

优点

  • 可以保证一个类只有一个实例。
  • 仅在首次请求单例对象时对其进行初始化。

缺点

  • 违反了单一职责原则,该模式同时解决了两个问题。
  • 在多线程环境下需要进行特殊处理,避免多个线程多次创建单例对象。

与其它模式的关系

  • 外观模式类通常可以转换为单例模式类,因为在大部分情况下一个外观对象就足够了。
  • 如果你能将对象的所有共享状态简化为一个享元对象,那么享元模式就和单例类似了。但这两个模式有两个根本性的不同。
    • 只会有一个单例实体。但是享元类可以有多个实体,各实体的内在状态也可以不同。
    • 单例对象可以是可变的。享元对象是不可变的。
  • 抽象工厂模式生成器模式原型模式都可以用单例来实现。

示例

示例一

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
}

示例二

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
}

示例三

饿汉模式,仅适用于实例的早期初始化工作已经确定时。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

var singleInstance *single

type single struct {
}

func init() {
	singleInstance = &single{}
}

References

guru