单例模式就是只能有一个实例化的对象的类。
当需要确保只有一个实例时,就要用到单例模式。
比如,当我们在项目中运用网络和数据库时,为了避免多模块重复创建网络连接或数据库实例,导致的资源浪费,我们就可以运用单例模式。
再比如,某些应用程序需要维护一个全局状态,例如游戏中的玩家信息、电子商务系统中的购物车。单例模式可以提供一个全局唯一的状态容器。
他的优点有:
保证实例唯一性,避免资源浪费。
提供全局访问点,简化代码结构。
可以严格控制客户端如何访问和使用实例。
缺点:
可能导致代码耦合度高,违反单一职责原则。
多线程环境下需要处理线程安全问题。
单元测试可能更困难,因为单例可能影响测试的独立性。
单例模式的实现:
#include<iostream>
using namespace std;
class Object
{
private:
static Object* pobject;
private:
Object(){}
Object(Object& ro){}
public:
~Object()
{
if (pobject != NULL)
{
pobject = NULL;
}
}
public:
static Object* GreatObject()
{
if (pobject == NULL)
{
pobject = new Object;
}
return pobject;
}
};
Object* Object::pobject = NULL;
int main()
{
Object* p1 =Object:: GreatObject();
Object* p2 =Object:: GreatObject();
return 0;
}
以上代码是单例模式中的懒汉模式:在第一次调用时检查并创建实例。
除了懒汉模式还有饿汉模式。
特性 | 饿汉模式(Eager) | 懒汉模式(Lazy) |
---|---|---|
实例创建时机 | 类加载时创建 | 首次调用时创建 |
线程安全性 | 天然线程安全(由类加载机制保证) | 非线程安全(需额外同步措施) |
资源利用率 | 可能浪费资源(即使未使用也会创建) | 资源利用率高(按需创建) |
实现复杂度 | 简单(无需考虑线程同步) | 复杂(需处理线程安全和内存管理) |
适用场景 | 单例对象初始化开销小、必须提前创建 | 初始化开销大、实例使用频率不确定 |
饿汉模式的实现:
#include<iostream>
using namespace std;
class Object
{
private:
// 静态实例对象,在类加载时初始化
static Object instance;
private:
// 私有构造函数
Object(){}
// 禁用拷贝构造函数
Object(const Object&) = delete;
// 禁用赋值运算符
Object& operator=(const Object&) = delete;
public:
// 析构函数不需要处理实例释放
~Object() = default;
// 全局访问点,返回静态实例的引用
static Object& getInstance()
{
return instance;
}
};
// 静态成员的初始化,在类外进行
Object Object::instance;
int main()
{
// 通过引用获取单例对象
Object& obj1 = Object::getInstance();
Object& obj2 = Object::getInstance();
// 输出验证地址相同
cout << "obj1 address: " << &obj1 << endl;
cout << "obj2 address: " << &obj2 << endl;
return 0;
}