第三课 设计模式之Singleton(单态)
单态是我感觉最常用到的设计模式了,所以这里咱们第一个来谈谈他。
Singleton模式主要作用是保证在应用程序中,一个类Class只有一个实例存在。那么,为什么要这样做呢,这样做有什么好处。下面我们来讨论下。
首先,很多情况下需要全局的唯一标识,作为一个应用程序的状态之类的作用。
其次,每个对象的实例化,都需要系统消耗一定的资源,如果全局使用一个对象能够满足要求的话,那么这无疑是节省资源的好方法。特别是像数据库连接这样的对象,多数都用单态来获得。既节省了内存开销,有方便垃圾回收机制回收对象。
下面我们来看看单态的实现方式。
(注意,从这里开始,我贴出的代码可能是C#,的也可能有很多是Java的代码,部分直接引用Java与模式中的代码,重点领会精神)
C#:
1. class Singleton {
2. public static Singleton Instance() {
3. if (_instance == null) {
4. lock (typeof(Singleton)) {
5. if (_instance == null) {
6. _instance = new Singleton();
7. }
8. }
9. }
10. return _instance;
11. }
12. protected Singleton() {
13. }
14. private static volatile Singleton _instance = null;
15. }
上面这段就是C#实现的一个懒单态模式。(为什么这么称呼别问我,我是这么看到的,估计因为实现太简单)
我们来分析下这段代码。
首先它定义了一个静态的对象 “_instance”
16. private static volatile Singleton _instance = null;
这里注意,有一个可能很多人没用过的关键字volatile 这个回头我们再解释。
然后有个静态方法 Instance() 返回单态对象。
里面判断 _instance 是否为null,如果为null则实例化他,返回,反之则直接返回 _instance 对象。
这就是基本的懒单态的处理方法。估计大家能够明白怎么保证全局只有一个实例对象的方法了吧。
下面谈谈细节。
首先,volatile关键字的意思是,放弃编译器编译时对代码重新排序,并且放弃优化。这是为什么呢?优化编译器可以将惰性初始化代码优化掉或对其重新进行排序,并且会重新产生线程安全问题。(总之会对多线程同时访问一个对象造成影响)这里的volatile就是声明放弃有话,保证多线程同时访问时值一定相同。
其次,
17. lock (typeof(Singleton)) {
这句是否很多人也没有使用过呢。这也是考虑到多线程访问时的安全问题,lock关键字,保证一个线程访问的时候进行锁定,别的线程处于阻塞(及等待状态),知道调用线程对该对象操作完毕。
现在我们这个单态可以说是完善的了,既能够保证全局有且仅有一个实例对象,又能保证其线程安全调用。
下面是java的一个实现。
Java
1. class Singleton {
2. public static Singleton Instance() {
3. if (_instance == null) {
4. synchronized (Class.forName("Singleton")) {
5. if (_instance == null) {
6. _instance = new Singleton();
7. }
8. }
9. }
10. return _instance;
11. }
12. protected Singleton() {
13. }
14. private static Singleton _instance = null;
15. }
貌似现在Java也有volatile 但是我没应用过,大家可以尝试一下。Java中线程会有一个共享对象的copy保存,所以这里用synchronized,目的是同步线程间的copy,作用同lock差不多,不过感觉不如lock保险(个人意见)。
这种LazySingleton 懒单态是最常见的。其实不牵扯到多线程的话,完全可以将volatile和Lock省略.
18. class Singleton {
19. public static Singleton Instance() {
20. if (_instance == null) {
21. _instance = new Singleton();
22. }
23. }
24. return _instance;
25. }
26. protected Singleton() {
27. }
28. private static Singleton _instance = null;
29. }
这样调用足够了。
其实单态还有一些复杂的设计方式,下面引用一段《java与模式》中的代码
Java
1. package com.javapatterns.singleton.demos;
2.
3.
4. import java.util.HashMap;
5.
6. public class RegSingleton {
7.
8. protected RegSingleton() {}
9.
10. static public RegSingleton getInstance(String name)
11. {
12. if (name == null)
13. {
14. name = "com.javapatterns.singleton.demos.RegSingleton";
15. }
16.
17. System.out.println("From RegSingleton: requesting for " + name );
18.
19. if (m_registry.get(name) == null)
20. {
21. try
22. {
23. m_registry.put( name, Class.forName(name).newInstance() ) ;
24. }
25. catch(ClassNotFoundException e)
26. {
27. System.out.println("Class " + name + " is not found.");
28. }
29. catch(InstantiationException e)
30. {
31. System.out.println("Class " + name + " can not be instantiated.");
32. }
33. catch(IllegalAccessException e)
34. {
35. System.out.println("Class " + name + " can not be accessed.");
36. }
37. }
38. return (RegSingleton) (m_registry.get(name) );
39. }
40.
41. static private HashMap m_registry = new HashMap();
42.
43. /**
44. * @label Creates
45. * @directed*/
46. /*# private RegSingletonChild lnkRegSingletonChild; */
47.
48. /**
49. * @label Creates
50. * @directed
51. */
52. /*# private RegSingleton lnkRegSingleton; */
53.
54. static
55. {
56. RegSingleton x = new RegSingleton();
57. m_registry.put( x.getClass().getName() , x);
58. }
59.
60. public String about()
61. {
62. return "Hello, I am RegSingleton.";
63. }
64.
65. }
66.
子类要实例话需要依靠父类,是为什么呢,自己体会吧。
本次单态课程结束。下节课讲工厂模式吧。
作者:王文斌
转载请注明出处。