单例模式顾名思义就是只能生成一个示例。其实在我个人不太成熟的理解上来说,单例模式的作用等同于在所有的成员变量和成员类前面加上一个“static”。所有调用这个类生成的实例都是同一个,因此我认为等同于将所有的类资源变成静态资源。
既然要有且仅有生成一个实例,那么我们需要做的就两件事。
1.将所有能够生成类实例的途径全部堵上,例如构造函数、拷贝构造函数私有化,外部无法访问也就无法通过他们生成实例了。
2.既然无法在外部生成类的实例,那么我们就需要想办法在类的内部生成类的实例,并且能够被我们所调用。
综上所诉,就可以得到一个简单的单例模式的例子了:
#include <iostream>
#define debug
class Single{
private:
Single(){
this->test = 0;
}
Single(const Single&){;}
Single& operator = (const Single&){;}
static Single* instance;
public:
static Single* getInstance();
int test;
};
Single* Single::instance = NULL;
Single* Single::getInstance(){
if(instance == NULL){
instance = new Single();
}
return instance;
}
int main(){
Single* single_1 = Single::getInstance();
Single* single_2 = Single::getInstance();
if(single_1 == single_2)
std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
#ifdef debug
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_1->test = 5;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_2->test = 10;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
#endif
std::cin.get();
return 0;
}
运行结果:
为了说明单例模式是成功的,代码先比较了“两个实例”的地址,程序输出结果表明地址是一致的。我们还在下面先后修改了single_1和Single_2实例中test的值,输出结果表明,sing_1和sing_2中test的值始终保持一致,也证明了仅生成了一个实例。
单例模式中还有一种称作是饿汉单例模式的分类,饿汉单例模式简单粗暴,在类内部直接生成一个实例,封堵其余生成实例的途径,以下是例子:
#include <iostream>
#define debug
class Single_hunger{
private:
Single_hunger(){
this->test = 0;
}
Single_hunger(const Single_hunger&){;}
Single_hunger& operator = (const Single_hunger&){;}
static Single_hunger* instance;
public:
static Single_hunger* getInstance();
int test;
};
Single_hunger* Single_hunger::instance = new Single_hunger();
Single_hunger* Single_hunger::getInstance(){
return instance;
}
int main(){
Single_hunger* single_1 = Single_hunger::getInstance();
Single_hunger* single_2 = Single_hunger::getInstance();
if(single_1 == single_2)
std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
#ifdef debug
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_1->test = 5;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_2->test = 10;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
#endif
std::cin.get();
return 0;
}
可以看出,饿汉单例和普通的单例模式的区别在于,普通单例的实例是在getInstance()函数中生成的,当且仅当访问这个函数的时候才会生成实例;而饿汉模式是在类的内部实现的,因此一开始就已经存在了这个实例,因此,饿汉模式的调用速度和反应速度更快,但是资源利用效率和系统加载时间上就表现比较差了。
同时,饿汉单例模式无需考虑多线程的影响,如果系统采用了多线程,那么普通的单例模式就不能满足系统的需求了。因为我们要创建实例,在多线程访问的情况下,我们需要加锁,这种模式叫懒汉模式,一下是例子:
#include<iostream>
#define debug
class Single_lazy{
private:
Single_lazy(){
this->test = 0;
}
static Single_lazy* instance;
Single_lazy(const Single_lazy&){;}
Single_lazy& operator = (const Single_lazy&){;}
static bool lock;
public:
int test;
static Single_lazy* getInstance();
};
Single_lazy* Single_lazy::instance = NULL;
bool Single_lazy::lock = false;
Single_lazy* Single_lazy::getInstance(){
if(instance == NULL){
/* 没有生成示例,首先上锁 */
if(!lock){
lock = true;
/* 第二次检测是否已经生成示例 */
if(instance == NULL){
instance = new Single_lazy();
}else;
lock = false;
}else;
}else;
return instance;
}
int main(){
Single_lazy* single_1 = Single_lazy::getInstance();
Single_lazy* single_2 = Single_lazy::getInstance();
if(single_1 == single_2)
std::cout << "single_1与single_2的地址一致" << std::endl << std::endl;
#ifdef debug
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_1->test = 5;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
single_2->test = 10;
std::cout << "single_1:" << single_1->test << std::endl;
std::cout << "single_2:" << single_1->test << std::endl << std::endl;
#endif
std::cin.get();
return 0;
}
懒汉模式在原有的普通单例模式的基础上增加了锁,保证有且仅有一个线程能够创建实例,避免了多线程导致创建多个实例出来。