设计模式之单例模式

单例模式

单例模式的概念

单例模式就是让一个类只存在一个实例对象,并给其他的对象提供这一个实例对象。

单例模式的特点

1.单例类只有而且只能有一个实例
2.单例类必须由自己创建这一个自己的唯一实例
3.单例类必须提供这一个实例给其他需要的对象

实现单例模式的方法

1.在单例类中定义一个私有静态属性
2.在类中定义一个公共静态存取函数(如:getInstance())
3.在访问器函数中执行"Lazy initialization(首次使用时创建)"
4.定义构造函数为protected或者private的
5.客户端只能使用访问器函数(如:getInstance())来操作单例

应用场景

只有满足一下三项时才应考虑使用单例模式

1.单一实例的所有权不能合理分配
2.懒惰初始化(就是需要使用的时候才进行初始化)是可取的
3.全局访问不另行规定

UML图

单例模式

单例模式的种类

1、懒汉型

这种类型只在第一次使用的时候实例化对象,后面需要对象时一直使用的这个对象,这个类的构造方法是私有的,所以无法在外部构造对象

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singeton{

private Singeton(){

}

private static Singleton single = null;

/**
*获取对象的方法,在第一次调用时实例化,第一次之后直接返回对象
*/
pubulic static Singleton getInstance(){
if(single == null){
single = new Singleton();
}

return single;
}
}
通过将构造方法限制为私有防止类子外部实例化,通过这种方法可以限制Singleton的唯一实例
只能通过getnstance()方法获取.

但是如果在多线程的情况下还是有可能出现多个Singleton实例的,所以我们应该在getnstance()加上同步

1
2
3
4
5
6
public synchronized static Singleton getInstance(){
if(Single == null){
single = new Singleton();
}
return single;
}

2、饿汉型

这种类型与上面不同的是唯一的对象在类创建的时候就已经初始化了,以后不会改变,所以没有线程的问题

代码:

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton{

private Singleton(){

}
//因为不再改变,所以直接置为final
private static final Singleton single = new Singleton();

public static Singleton getInstance(){
return single;
}
}

3、登记式

不常用,由hashmap存储,代码麻烦,还不会

抄的代码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
public class Singleton3 {
private static Map<String, Singleton3> map = new HashMap<String, Singleton3>();

static {
Singleton3 single = new Singleton3();
map.put(single.getClass().getName(), single);
}

//保护的默认构造方法
protected Singleton3() {
}

//静态工厂方法,返还此类惟一的实例
public static Singleton3 getInstance(String name) {
if (name == null) {
name = Singleton3.class.getName();
System.out.println("name == null" + "--->name=" + name);
}
if (map.get(name) == null) {
try {
map.put(name, (Singleton3) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return map.get(name);
}

//一个示意性的商业方法
public String about() {
return "Hello, I am RegSingleton.";
}

public static void main(String[] args) {
Singleton3 single3 = Singleton3.getInstance(null);
System.out.println(single3.about());

}
}

登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。 这里对登记式单例标记了可忽略,首先它用的比较少,另外其实内部实现还是用的饿汉式单例,因为其中的static方法块,它的单例在类被装载的时候就被实例化了。

单例模式的作用

由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点, 不管它实现何种功能,整个应用程序都会同享一个实例对象。在android的APP中经常用到这种模式 ,在这个程序中,这个类的对象就是全剧唯一的。