单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其默认构造函数和拷贝构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
思路总结:
1、构造函数私有化:如果没有私有化,就可以创建多个对象实例,与目标(保证只有一个对象实例)不符;
2、静态类指针私有化:如果没有私有化,可能会被置为NULL,因为是static类型,就是共享数据;
3、提供公有的静态get方法,因为要获取到私有的静态指针属性。
4、私有的静态指针需要在类外进行初始化;
5、为防止拷贝对象出现对象实例不一致问题,所以将拷贝构造也私有化。
注意:静态成员变量只能在类外初始化(分配内存)。因为静态成员变量先于该类任何对象的存在而存在,它被该类所有的对象共享。
单例模式案例1----主席案例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//创建主席类
//需求 单例模式 为了创建类中的对象,并且保证只有一个对象实例。
class ChairMan
{
//1构造函数 进行私有化
private:
ChairMan()
{
//cout << "创建国家主席" << endl;
}
//拷贝构造函数也私有化
ChairMan(const ChairMan&c)
{
}
//public:
static ChairMan * singleMan;
public:
//提供get方法 访问 主席
static ChairMan * getIstance()
{
return singleMan;
}
};
ChairMan * ChairMan::singleMan = new ChairMan;
void test01()
{
/*ChairMan c1; //栈上创建一个国家主席
ChairMan * c2 = new ChairMan;
ChairMan * c3 = new ChairMan;*/
//ChairMan::singleMan;
/*ChairMan * cm = ChairMan::singleMan;
ChairMan * cm2 = ChairMan::singleMan;*/
//ChairMan::singleMan = NULL; //共享的数据被置为NULL
ChairMan * cm1 = ChairMan::getIstance();//返回的指针不可能为NULL
ChairMan * cm2 = ChairMan::getIstance();
if (cm1 == cm2)
{
cout << "cm1和cm2相同" << endl;
}
else
{
cout << "cm1和cm2不同" << endl;
}
//ChairMan * cm3 = new ChairMan(*cm2); 解决办法:拷贝构造函数私有化
/*if (cm3 == cm2)
{
cout << "cm3和cm2相同" << endl;
}
else
{
cout << "cm3和cm2不同" << endl;
}*/
}
int main(void)
{
//cout << "main调用" << endl; 主席先于main调用
test01();
system("pause");
return 0;
//return EXIT_SUCCESS;
}
单例模式案例2----打印机
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
class Printer
{
private:
Printer(){ m_Count = 0; };
Printer(const Printer&p);
public:
static Printer* getInstance()
{
return singleprinter;
}
void printText(string text)
{
cout << text << endl;
m_Count++;
cout << "打印机使用了次数为:" << m_Count << endl;
}
private:
static Printer* singleprinter;
int m_Count;
};
Printer* Printer::singleprinter = new Printer;
void test01()
{
//拿到打印机
Printer * printer = Printer::getInstance();
printer->printText("离职报告");
printer->printText("入职报告");
printer->printText("加薪报告");
printer->printText("升职报告");
printer->printText("退休");
}
int main(void)
{
test01();
system("pause");
return 0;
}
饿汉式
在程序启动时就创建单例对象,这种实现方法的优点是线程安全,因为再程序启动时就已经创建了单例对象,所以不需要考虑多线程同步问题。缺点是可能造成资源浪费,因为即使程序中并没有使用单例对象,它也已经被创建了。
class Singleton
{
private:
Singleton(){}
static Singleton* instance;
public:
static Singleton* getInstance()
{
return instance;
}
};
Singleton* Singleton::instance = new Singleton();
懒汉式
只有当需要使用单例对象时才创建,这种方法优点是节省资源。因为只有在需要使用单例对象时才进行创建。但需要考虑线程安全问题,否则可能造成多个线程同时创建单例对象。
class Singleton
{
private:
Singleton(){}
static Singleton* instance;
public:
static Singleton* getInstance()
{
if(instance == nullptr)
{
instance = new Singleton();
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
线程安全问题可以通过加锁解决std::mutex
class Singleton
{
private:
Singleton(){}
static Singleton* instance;
static std::mutex mtx;
public:
static Singleton* getInstance()
{
if(instance == nullptr)
{
std::lock_guard<std::mutex> lock(mtx);
if(instance == nullptr)
{
instance = new Singleton();
}
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;