编程-设计模式教程

单例模式

确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。

1)特点

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。

2)应用场景

  • 频繁访问数据库或文件的对象。
  • 工具类对象;
  • 创建对象时耗时过多或耗费资源过多,但又经常用到的对象;

3)优点

  • 内存中只存在一个对象,节省了系统资源。
  • 避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。

4)缺点

  • 获取对象时不能用new
  • 单例对象如果持有Context,那么很容易引发内存泄露。
  • 单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。

5)实现

(1)推荐方案

Java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private Singleton() {
}

public static Singleton getInstance() {
//第一次调用getInstance方法时才加载SingletonHolder并初始化sInstance
return SingletonHolder.sInstance;
}

//静态内部类
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}

C++:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// version 1.2
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};

(2) 饿汉式

1
2
3
4
5
6
7
8
9
10
11
12
//单例类.   
public class Singleton {

private Singleton() {//构造方法为private,防止外部代码直接通过new来构造多个对象
}

private static final Singleton single = new Singleton(); //在类初始化时,已经自行实例化,所以是线程安全的。

public static Singleton getInstance() { //通过getInstance()方法获取实例对象
return single;
}
}
  • 优点:写法简单,线程安全。
  • 缺点:没有懒加载的效果,如果没有使用过的话会造成内存浪费。

(3) 懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//单例类
public class Singleton {
private Singleton() {
}

private static Singleton single = null;

public static Singleton getInstance() {
if (single == null) {
single = new Singleton(); //在第一次调用getInstance()时才实例化,实现懒加载,所以叫懒汉式
}
return single;
}
}
  • 优点:实现了懒加载的效果。
  • 缺点:线程不安全。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//单例类
public class Singleton {
private Singleton() {
}

private static Singleton single = null;

public static synchronized Singleton getInstance() { //加上synchronized同步
if (single == null) {
single = new Singleton();
}
return single;
}
}
  • 优点:实现了懒加载的效果,线程安全。
  • 缺点:使用synchronized会造成不必要的同步开销,而且大部分时候我们是用不到同步的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private volatile static Singleton singleton; //volatile 能够防止代码的重排序,保证得到的对象是初始化过

private Singleton() {
}

public static Singleton getSingleton() {
if (singleton == null) { //第一次检查,避免不必要的同步
synchronized (Singleton.class) { //同步
if (singleton == null) { //第二次检查,为null时才创建实例
singleton = new Singleton();
}
}
}
return singleton;
}
}
  • 优点:懒加载,线程安全,效率较高
  • 缺点:volatile影响一点性能,高并发下有一定的缺陷,某些情况下DCL会失效,虽然概率较小。