单例模式(创建型模式)
模式概述
单例模式
是一种创建型设计模式,它能够保证一个类在整个应用生命周期内之有且仅有一个实例,并提供一个获得该实例的方法。
问题
当人们买了房子之后,不管在哪个行政服务中心的窗口,都只会发一份相同的证明,盖一份一样的公章,这是因为政府机构是唯一的,不然就乱套了。
一般来说,一个男人既是儿子,又是丈夫,同时还会是父亲和爷爷,也许还可能是哥哥或弟弟。如果亮出这些身份的时候都不是同一个人,那会相当麻烦(女人也一样)。
大多数网站会用访问计数器来统计浏览量,如果每次访问网站都开启一个全新的计数器,那么无论什么时候看,网站的总访问量永远都停留在
1
这个数字上。所以必须使用一个全局唯一的计数器来保证浏览人数总是以累加的形式存在的。当需要某个对象能够被多个应用共享,且这个对象还需要从始至终保留共享的状态,那么就只能以一个全局唯一的实例来提供服务,如Web配置对象、数据库连接池等。
对于以上这些场景,都必须通过一个有且仅有一个
的对象才能实现。

方案
单例模式(Singleton Pattern)会为指定的对象 生成且仅生成全局唯一的实例。
不过,创建实例的职责一般都会由这个该类自己承担——因为只有自己才最了解自己。
它会在创建时先判断是否已经有实例存在。
如果已存在实例,那么就直接返回之前创建过的实例的引用。
如果不存在实例,那么就新创建一个实例并且返回该实例的引用。
结构


实现
Java
/**
* 基础单例:单线程
*
*/
public final class Singleton {
private static Singleton instance;
public String value;
private Singleton(String value) {
this.value = value;
}
public static synchronized Singleton getInstance(String value) {
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
public static void main(String[] args) {
// 这里只能看到"one"
Singleton singleton = Singleton.getInstance("one");
Singleton anotherSingleton = Singleton.getInstance("two");
System.out.println(singleton.value);
System.out.println(anotherSingleton.value);
}
}
/**
* 基础单例:多线程
*
*/
public final class Singleton {
private static Singleton instance;
public String value;
private Singleton(String value) {
this.value = value;
}
public static synchronized Singleton getInstance(String value) {
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
public static void main(String[] args) {
// 结果取决于哪个线程先运行,先运行one,结果就是one;先运行two,结果就是two
new Thread(new Runnable() {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("one");
System.out.println(singleton.value);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("two");
System.out.println(singleton.value);
}
}).start();
}
}
Go
package main
import (
"fmt"
"sync"
)
var lock = &sync.Mutex{}
var singleInstance *single
type single struct {}
/**
* 为了显示出效果,多加了打印语句
*
*/
func getInstance() *single {
if singleInstance == nil {
lock.Lock()
defer lock.Unlock()
if singleInstance == nil {
fmt.Println("实例化单例对象")
singleInstance = &single{}
} else {
fmt.Println("单例对象已创建")
}
} else {
fmt.Println("单例对象已创建")
}
return singleInstance
}
func main() {
for i := 0; i < 30; i++ {
go getInstance()
}
fmt.Scanln()
}
这里有关于单例模式的最佳实践和样例。
适用场景
如果需要某个类在整个应用的生命周期内只能存在一个实例,那么毫无疑问应该使用单例模式。
如果需要严格地控制全局变量,就可以使用单例模式。单例类倒是个可以保存全局变量的场所。
有限单例和线程池或数据库连接池是不同的,它只不过是稍微增加了一些实例的数量而已。
优缺点
单例模式的优点。
可以保证一个类
有且仅有
单个实例。有两种初始化模式。
单例模式的缺点。
缺乏抽象层,扩展困难。
违背
单一职责原则
:既创建对象,又持有对象。
相关性
外观模式
有点类似于单例模式
,因为这个外观
提供了一个统一的入口。抽象工厂模式
中的工厂类、构建器模式
中的构造器,以及原型模式
中的原型,都可以用单例模式
来实现。
感谢支持
更多内容,请移步《超级个体》。