一.概述
1.什么是单例模式
单例模式(Singleton Pattern)是一种设计模式,用于确保一个类只有一个实例,并提供全局访问点以访问该实例。
在应用程序的整个生命周期内,只能创建一个特定类的对象。
单例模式常用于需要共享资源或控制共享某些资源的情况,以确保资源的一致性和有效管理。
例如一般一个程序中只有一个日志输出实例,一个系统中只有一个数据库连接实例,这时候用单例模式非常合适。
2.单例模式通常包括要素
私有构造函数:单例类通常将其构造函数设为私有,以防止外部代码直接实例化类的对象。
静态成员变量:单例类通常包含一个私有的静态成员变量,用于存储类的唯一实例。
静态成员函数:单例类通常包含一个公共的静态成员函数,通常命名为 getInstance() 或 Instance(),用于获取单例类的实例。
说明:用getInstance或者Instance没有区别,但从直观理解上用getInstance更好一点
延迟初始化:在首次调用 getInstance() 方法时才创建类的唯一实例,以延迟初始化。
线程安全性:如果在多线程环境中使用单例模式,需要确保线程安全性,以防止多个线程同时创建实例。通常可以使用互斥锁等机制来实现线程安全性。
3.单例模式的 优 点和缺点
优点:
提供全局访问点,方便在应用程序的不同部分共享对象。
确保只有一个实例存在,节省资源。
提供对单一资源或配置的集中管理。
支持懒加载,只在需要时创建实例。
缺点:
可能导致全局状态,增加了代码的耦合性。
在某些情况下可能会引入单点故障。
难以进行单元测试,因为单例对象难以模拟或替代。
二.代码实现
1.简单的单例实现
(1)test.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QString>
class MyWidget : public QWidget {
Q_OBJECT
public:
static MyWidget* getInstance();
void updateData(const QString& data);
private:
MyWidget(QWidget* parent = nullptr);
static MyWidget* instance;
};
#endif // MYWIDGET_H
(2)test.cpp
#include "test.h"
#include <QDebug>
MyWidget* MyWidget::instance = nullptr;
MyWidget* MyWidget::getInstance() {
if (!instance) {
instance = new MyWidget();
}
return instance;
}
MyWidget::MyWidget(QWidget* parent) : QWidget(parent) {
// 初始化界面部件
}
void MyWidget::updateData(const QString& data)
{
qDebug()<<"display:"<<data;
}
(3)调用
#include "test.h"
MyWidget* myWidget = MyWidget::getInstance();
myWidget->updateData("Some data to display");
//或者
MyWidget::getInstance()->updateData("Some data to display");
2.线程安全的单例示例
(1)test.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QString>
class MyWidget : public QWidget {
Q_OBJECT
public:
static MyWidget* getInstance();
void updateData(const QString& data);
private:
MyWidget(QWidget* parent = nullptr);
static QScopedPointer<MyWidget> self;
};
#endif // MYWIDGET_H
(2)test.cpp
#include "test.h"
#include <QDebug>
#include "qmutex.h"
QScopedPointer<MyWidget> MyWidget::self;
MyWidget *MyWidget::getInstance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new MyWidget);
}
}
return self.data();
}
MyWidget::MyWidget(QWidget* parent) : QWidget(parent) {
// 初始化界面部件
}
void MyWidget::updateData(const QString& data)
{
qDebug()<<"display:"<<data;
}
(3)调用
#include "test.h"
MyWidget::getInstance()->updateData("Some data to display");