學習設計模式,自然從最簡單的模式入手,而最簡單的模式便是Singleton.所以第一篇就來所以說Singleton模式.看完GOF和Design patterns in Java的書,感覺Singleton雖然簡單,但是想寫出一個好的Singleton也不是一上來就能寫出來的.
Singleton模式的用處自然是保證一個類只有一個唯一的實例.在建模中涉及到的只能有一個對象,例如Struts中的Action類就是一例.除此之外,Singleton還是的該對象只有一個全局訪問點.這就是SIngleton的作用.
說得比較抽象,我們來看一個簡單Singleton的C 和Java的代碼:
C Singleton模式:
類定義:
1.class Singleton
2.{
3.public:
4. static Singleton * Instance();
5. ~Singleton();
6.
7.private:
8. Singleton();
9.
10. static Singleton * instance;
11.};
方法實現:
12.Singleton * Singleton::instance = 0;
13.
14.Singleton::Singleton()
15.{
16.
17.}
18.
19.Singleton::~Singleton()
20.{
21.
22.}
23.
24.Singleton * Singleton::Instance()
25.{
26. if (instance == 0) {
27. instance = new Singleton();
28. }
29.
30. return instance;
31.}
Java Singleton模式:
32.public class Singleton {
33.
34. private static Singleton instance;
35.
36. public static Singleton getInstance() {
37. if (instance == null)
38. instance = new Singleton();
39.
40. return instance;
41. }
42.
43. /** *//** Creates a new instance of Singleton */
44. private Singleton() {
45. }
46.}
通過上面的例子可以看出,Singleton的實現並不難,只要將構造函數訪問域設為私有,然後添加一個靜態引用和一個獲得該應用的靜態方法即可.其實在C 中定義一個全局靜態變數也可以達到這個效果,但是像Java這樣的語言就是能使用Singleton了.
上面的程序有一個問題,就是只能運行在單線程的環境下.為此我在C 上作了個實驗.
#include .在SIngleton::Instance()函數中增加一個Sleep(1000),程序如下:
47.Singleton * Singleton::Instance()
48.{
49. if (instance == 0) {
50. Sleep(1000);
51. instance = new Singleton();
52. }
53.
54. return instance;
55.}
然後在主函數中創建兩個線程,程序如下:
56.static Singleton * s1 = 0, * s2 = 0;
57.
58.DWORD WINAPI ThreadProc1(PVOID)
59.{
60. s1 = Singleton::Instance();
61.
62. return 0;
63.}
64.
65.DWORD WINAPI ThreadProc2(PVOID)
66.{
67. s2 = Singleton::Instance();
68.
69. return 0;
70.}
71.
72.int main(int argc, char* argv[])
73.{
74. DWORD threadID1;
75. DWORD threadID2;
76.
77. CreateThread(NULL, 0, ThreadProc1, NULL, 0, &threadID1);
78. CreateThread(NULL, 0, ThreadProc2, NULL, 0, &threadID2);
79.
80. Sleep(10000);
81.
82. std::cout << s1 << " " << s2;
83.
84. return 0;
85.}
這樣修改後在運行程序,列印出來的s1和s2地址就不是同一個地址了.結果如下:
0372D68 00372E68Press any key to continue
可見當在多線程環境下使用這個Singleton就會出現創建不止一個實力的情況,所以我們需要給Singleton加鎖.請看下面的代碼.
C Singleton模式:
86.class Singleton
87.{
88.public:
89. static Singleton * Instance();
90. virtual ~Singleton();
91.
92.private:
93. Singleton();
94.
95. static CMutex mutex;
96. static Singleton * instance;
97.};
98.Singleton * Singleton::instance = 0;
99.CMutex Singleton::mutex;
100.
101.Singleton::Singleton()
102.{
103.
104.}
105.
106.Singleton::~Singleton()
107.{
108.
109.}
110.
111.Singleton * Singleton::Instance()
112.{
113. mutex.Lock();
114.
115. if (instance == 0) {
116. Sleep(1000);
117. instance = new Singleton();
118. }
119.
120. mutex.Unlock();
121.
122. return instance;
123.}
此外需要#include < afxmt.h>,,並且在項目設置中要設置動態鏈接MFC庫.
Java Singleton模式:
124.public class Singleton {
125.
126. private static Singleton instance;
127. private static Object lock = Singleton.class;
128.
129. public static Singleton getInstance() {
130. synchronized (lock) {
131. if (instance == null)
132. instance = new Singleton();
133.
134. return instance;
135. }
136. }
137.
138. /** *//** Creates a new instance of Singleton */
139. private Singleton() {
140. }
141.}
運用加鎖就可以解決在多線程環境下使用Singleton模式所帶來的問題了.