單件模式是一種較為簡(jiǎn)單的創(chuàng)建型模式,在日常的開(kāi)發(fā)中也常常使用。目的是在應(yīng)用程序中保證某個(gè)類(lèi)的對(duì)象僅能有一個(gè)。在C++的世界中,因?yàn)樗皇羌兠嫦驅(qū)ο蟮恼Z(yǔ)言,它支持全局變量的特性,所以在許多的場(chǎng)合它可以用全局變量來(lái)替代。非常典型的例子就是在MFC的應(yīng)用程序中的theAPP對(duì)象,它就是一個(gè)全局的唯一對(duì)象。類(lèi)似這樣的例子在C++的程序中有許多,在C++中存在這樣的現(xiàn)象是有一定的原因。這里先介紹一個(gè)基于C++實(shí)現(xiàn)的單件模式例子。
1
#pragma once
2
#include <deque>
3
4
/**/////////////////////////////////////////////////////////////////////////// 5
// Forward declaration
6
//
7
//
8
/**/////////////////////////////////////////////////////////////////////////// 9
class CSendJob;
10
class JobDeque;
11
12
/**//// <summary>
13
/// 本類(lèi)為作業(yè)啟動(dòng)信息儲(chǔ)存體
14
/// 此類(lèi)僅為JobDeque所使用,不宜讓其它客戶使用
15
/// </summary>16
class JobStartInformation
17

{
18
friend class JobDeque;
19
public:
20
~JobStartInformation()
21
{
22
//Don`t delete the m_pJob pointer.
23
}
24
25
private:
26
JobStartInformation(CSendJob *pJob, BOOL bManual)
27
:m_pJob(pJob),
28
m_bManualStart(bManual)
29
{
30
}
31
32
public:
33
CSendJob* GetJob() const
{ return m_pJob; }
34
BOOL IsManualStart() const
{ return m_bManualStart; }
35
36
private:
37
BOOL m_bManualStart;
38
CSendJob *m_pJob;
39
};
40
41
class JobDeque
42

{
43
// Constructor and Destructor
44
public:
45
private:
46
virtual ~JobDeque(void);
47
private:
48
JobDeque(void);
49
JobDeque(const JobDeque &);
50
JobDeque& operator=(const JobDeque& );
51
52
// Methods:
53
public:
54
void Start( CSendJob *pJob, BOOL bManualStart);
55
void Completed( CSendJob* pJob);
56
private:
57
void Launch();
58
private:
59
USHORT m_usRunAmount;
60
std::deque<JobStartInformation > m_jobDeque;
61
62
public:
63
static JobDeque* GetJobDeque();
64
static void DestroyJobDeque();
65
66
private:
67
/**////<summary>
68
/// 可以并行執(zhí)行的作業(yè)數(shù)目
69
///</summary>
70
static const USHORT m_susParallelAmount;
71
static JobDeque *m_spJobDeque;
72
73
#ifdef _DEBUG
74
void Validate();
75
#else
76
void Validate()
77
{
78
}
79
#endif
80
};
81
1
#include "StdAfx.h"
2
#include <algorithm>
3
#include "SendJob.h"
4
#include "JobDeque.h"
5
using namespace std;
6
7
// JobDeque.cpp
8
/**////<summary>
9
/// 這里僅對(duì)全局唯一的作業(yè)對(duì)象地址作比較
10
///</summary> 11
bool operator==(const JobStartInformation& lo, const JobStartInformation& ro) throw()
12

{
13
if(&lo == &ro)
14
{
15
return true;
16
}
17
18
if(NULL ==lo.GetJob() && NULL == ro.GetJob())
19
{
20
return true;
21
}
22
if(NULL == lo.GetJob() || NULL == ro.GetJob())
23
{
24
return false;
25
}
26
return lo.GetJob() == ro.GetJob();
27
}
28
29
bool operator!=(const JobStartInformation& lo, const JobStartInformation& ro) throw()
30

{
31
return !(lo == ro);
32
}
33
34
bool operator<(const JobStartInformation& lo, const JobStartInformation& ro) throw()
35

{
36
if(lo == ro)
37
{
38
return true;
39
}
40
return lo.GetJob() < ro.GetJob();
41
}
42
43
44
/**/////////////////////////////////////////////////////////////////////////// 45
// 靜態(tài)變量
46
const USHORT JobDeque::m_susParallelAmount = 1;
47
JobDeque* JobDeque::m_spJobDeque = NULL;
48
49
/**/////////////////////////////////////////////////////////////////////////// 50
// Constructor and Destructor
51
//
52
//
53
//
54
/**/////////////////////////////////////////////////////////////////////////// 55
JobDeque::JobDeque(void)
56

{
57
m_usRunAmount = 0;
58
}
59
60
JobDeque::~JobDeque(void)
61

{
62
}
63
64
/**/////////////////////////////////////////////////////////////////////////// 65
//
66
//
67
//
68
/**/////////////////////////////////////////////////////////////////////////// 69
void JobDeque::Start( CSendJob *pJob, BOOL bManualStart)
70

{
71
ATLASSERT(pJob && _T("Argument of pJob is NULL in JobDeque::Start."));
72
if(!pJob)
73
{
74
return;
75
}
76
77
JobStartInformation jobInfo(pJob, bManualStart);
78
deque<JobStartInformation >::iterator itFinder = find(m_jobDeque.begin(), m_jobDeque.end(), jobInfo);
79
if(itFinder == m_jobDeque.end())
80
{
81
m_jobDeque.push_back(jobInfo);
82
pJob->SetSyncState(CSendJob::COPYING);
83
}
84
Launch();
85
return;
86
}
87
88
void JobDeque::Completed( CSendJob* pJob )
89

{
90
ATLASSERT(pJob && _T("Argument of pJob is NULL in JobDeque::Start."));
91
if(!pJob)
92
{
93
return;
94
}
95
--m_usRunAmount;
96
Validate();
97
Launch();
98
return;
99
}
100
101
void JobDeque::Launch()
102

{
103
if(m_usRunAmount < m_susParallelAmount && m_jobDeque.size() > 0)
104
{
105
m_jobDeque.front().GetJob()->Send(m_jobDeque.front().IsManualStart());
106
m_jobDeque.pop_front();
107
++m_usRunAmount;
108
Validate();
109
}
110
}
111
112
JobDeque* JobDeque::GetJobDeque()
113

{
115
if (NULL == m_spJobDeque)
116
{
117
if 進(jìn)入互斥區(qū)成功
118
{
119
if(NULL == m_spJobDeque)
120
{
121
m_spJobDeque = new JobDeque();
122
}
退出斥區(qū)
123
}
132
}
133
return m_spJobDeque;
134
}
135
136
void JobDeque::DestroyJobDeque()
137

{
138
if(m_spJobDeque)
139
{進(jìn)入互斥區(qū)
140
delete m_spJobDeque;
141
m_spJobDeque = 0;
退出互斥區(qū)
142
}
143
}
144
145
#ifdef _DEBUG
146
void JobDeque::Validate()
147

{
148
if(m_susParallelAmount < m_usRunAmount || m_usRunAmount < 0)
149
{
150
ATLASSERT(_T("The counter in JobDeque work error!"));
151
}
152
}
153
#endif
154
在這里就省略全局實(shí)例的的例子,在上面的例子中不僅有取得實(shí)例的靜態(tài)函數(shù),還有銷(xiāo)毀實(shí)例的靜態(tài)函數(shù)。客戶可以任何地方及任何時(shí)間調(diào)用獲得單件的函數(shù),但是用戶只能且必須在應(yīng)用程序的最后出口處調(diào)用釋放實(shí)例的函數(shù)。也曾看過(guò)C++實(shí)現(xiàn)的單件模式的例子,例子中沒(méi)有銷(xiāo)毀函數(shù)。這與C#,JAVA這樣的純面向?qū)ο髮?shí)現(xiàn)的例子非常地相似。可是C++中并沒(méi)有自動(dòng)垃圾回收裝置,所以還是要我們自己在某個(gè)地方銷(xiāo)毀new出來(lái)的這個(gè)全局實(shí)例對(duì)象。在上面可以看出C++實(shí)現(xiàn)的單件模式不及全局變量來(lái)得簡(jiǎn)單而高效。我持有這個(gè)觀點(diǎn)是基于以下兩個(gè)方面的考慮
(1) 利用全局變量的方案來(lái)產(chǎn)生全局唯一實(shí)例時(shí)不用考慮多線程的情況,在上面的例子中產(chǎn)生實(shí)例時(shí)考慮了多線程情況。
(2) 利用全局變量的方案產(chǎn)生的實(shí)例對(duì)象會(huì)在程序退出時(shí)自動(dòng)地銷(xiāo)毀對(duì)象,而單件模式需明確地delete實(shí)例。
這里并沒(méi)有斷言全局變量就優(yōu)于單件模式,出于如下的考慮可能又會(huì)選用單件模式
(1) 全局變量的方式使代碼的耦合度提高了,而且需事先總體設(shè)計(jì)好。須保證開(kāi)發(fā)人員和后續(xù)的維護(hù)人員不能再去產(chǎn)生的新的實(shí)例,theApp全局實(shí)例是MFC世界基礎(chǔ)的知識(shí)了。
(2) 單件實(shí)例的構(gòu)造函數(shù)的參數(shù)中需要自定義對(duì)象實(shí)例時(shí)也會(huì)迫使開(kāi)發(fā)人員選用單件模式。
我認(rèn)為兩種方案都有優(yōu)點(diǎn)和缺點(diǎn),不能說(shuō)一個(gè)方案絕對(duì)地優(yōu)于另外一個(gè)方案。究竟選用哪種方案取決于應(yīng)用的環(huán)境的約束以及開(kāi)發(fā)人員的偏好。這里闡述了一些個(gè)人的觀點(diǎn),希望能起到拋磚引玉的作用。