单例模式
引入
对于系统中的某些类来说,只有一个实例很重要,例如,
- 一个班只能由一个班主任;
- 一个国家只能有一位总统;
概念
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
保证类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享
单例模式的要点有三个:
- 单例类只能有一个实例
- 必须自行创建这个实例
- 必须自行向整个系统提供这个实例
实现步骤
- 构造函数私有化
- 提供一个全局的静态方法(全局访问点)
- 在类中定义一个静态指针,指向本类的变量的静态变量指针。
只能有一个实例
注意点
- 实例控制: 单例模式会阻止其他对象实例化自己的单例对象的副本,从而确保所有对象都访问唯一实例
- 灵活性: 因为类控制实例化过程,所以类可以灵活更改实例化过程
- 开销: 虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销,这个问题可以通过静态初始化解决此问题。定义一个私有的静态指针instance,和一个公有的静态函数 GetInstance()。
优点
- 在内存中只有一个对象,节省内存空间
- 避免频繁的创建销毁对象,可以提高性能
- 避免对共享资源的多重占用
- 可以全局访问
适用场景
- 需要频繁实例化然后销毁的对象
- 创建对象耗时过多或者耗资源过多,但又经常用到的对象
- 有状态的工具类对象
- 频繁访问数据库或文件的对象
- 以及其他要求只有一个对象的场景
实现
#include <iostream>
#include <string>
using namespace std;
class Pressident
{
private:
Pressident(); //默认构造函数
Pressident(const Pressident&){}; //复制构造函数
const Pressident& operator=(const Pressident&){}; //赋值函数
string name;
public:
static Pressident& GetInstance() //静态成员函数
{
static Pressident onlyInstance; //静态成员变量
return onlyInstance;
}
string GetName()
{
return name;
}
void setName(string InputName)
{
name = InputName;
}
};
int main()
{
Pressident& onlyPresident = Pressident::GetInstance();
onlyPresident.setName("Abraham Lincoln");
// Pressident second; //实例化时调用默认构造函数,但构造函数为私有,所以无法创建该对象
// Pressident *third = new Pressident(); //实例化时调用默认构造函数,但构造函数为私有,所以无法创建该对象
// Pressident fourth = onlyPresident; //通过复制构造函数创建现有对象的拷贝(在创建对象的同时调用复制构造函数)
// onlyPresident = Pressident::GetInstance();//通过赋值创建对象的拷贝;但构造函数为私有,所以无法创建该对象
cout << "The name of the President is: ";
cout << Pressident::GetInstance().GetName() << endl;
return 0;
}
分析
- 将构造函数、复制构造函数、赋值构造函数设置为private属性,保证在main()函数中无法创建对象,也保证了单例中实例在类自身中定义;
- 设置static Pressident& GetInstance()静态成员函数,保证该函数在所有成员中共享,【static+类的成员函数,使得函数与类的任何对象独立开来,即使在类的对象不存在的情况下,也可以通过在静态成员函数前面加范围解析运算符::访问,达到共享的目的,如:Pressident::GetInstance()】
- Pressident& onlyInstance;在类中实现实例化,创建唯一的一个对象;
- 静态成员函数只能访问静态类成员变量,因此GetInstance()可以访问到静态成员变量onlyInstance;