单例模式也称单件模式,单子模式,是使用最广泛的设计模式之一;意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
一、单例模式
用户访问唯一实例的方法只有getInstance()成员函数。如果不通过这个函数,任何创建的尝试都将失败,因为类的构造函数是私有的。getIntance()使用懒惰初始化,也就是说它的返回值是当这个函数首次访问时被创建。这是一种防弹设计-------所有getInstance()之后的调用都返回相同实例的指针。
#include <iostream>
#include <string>
using namespace std;
class Master
{
public:
static Master* getInstance(char* name,int age)//公有的接口;必须是静态的,不依赖对象的调用;
{//判断是否是第一次调用
if(pma == NULL)
{
pma = new Master(name,age);
}
return pma;
}
private:
Master(char* name,int age):mname(new char[strlen(name) + 1])//将生成对象的构造的函数放在私有下;
{
strcpy(mname,name);
mage = age;
}
Master(const Master&);//将拷贝构造函数屏蔽,因为拷贝构造函数是用已存在的对象生成新的对象;
char* mname;
int mage;
static Master* pma;//静态数据成员,类中声明,类外必须定义
};
Master* Master::pma = NULL;//静态变量必须在类外进行初始化;
int main()
{
Master* pmal = Master::getInstance("zhangsan",20);
Master* pmal2 = Master::getInstance("lisi",35);
}
调试结果:
单例模式有以下的特征:
●它有一个指向唯一实例的静态指针pma,并且是私有的;
●它有一个公用的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;
●它的构造函数是私有的,这样就不能从别处创建该类的实例
二、双重锁机制单例模式
但是在多线程的情况下,静态接口函数会发生线性不安全,导致生成两个对象;
所以要对此函数加锁,如下:
static Master* getInstance(char* name,int age)//公有的接口;必须是静态的,不依赖对象的调用;
{//判断是否是第一次调用
if(psing == NULL)//如果不加此判断,每次需要实例化时都需要加锁解锁;导致效率低,所以不管有没有生成对象都要进行判断
//lock()
{
if(psing == NULL)
{
psing = new Master(name,age);
}
return psing;
}
//unlock()
}
三、提前生成对象
线程依赖进程,在进程开始之前生成对象,就不存在线程安全问题;而数据段是在代码加载时就已经生成的,根据数据段的这一特点,我们可以在代码加载时就生成对象,也就是将创建的对象放在数据段中;代码如下:
#include <iostream>
#include <string>
using namespace std;
class SingleTon
{
public:
static SingleTon& getInstance()
{
return single;
}
private:
SingleTon(){}//屏蔽构造函数
SingleTon(const SingleTon&);//拷贝构造函数的声明
static SingleTon single;//.data段的对象不能放在类外,在类外就看不见构造方法;加static不依赖对象,
};
SingleTon SingleTon::single;//一旦初始化就调用默认的构造方法生成对象
int main()
{
SingleTon& single1 = SingleTon::getInstance();
SingleTon& single2 = SingleTon::getInstance();
SingleTon& single3 = SingleTon::getInstance();
SingleTon& single4 = SingleTon::getInstance();
}
调试结果:
主要特征:
●在类的私有限定符下,定义静态对象,并在类外进行初始化;
●在静态方法中将生成的对象返回