前言
本文主要讲述了使用加锁的懒汉式来实现单例,文中示例将一个界面类修改为单例类,并在主界面获取多次该类的实例来进行测试,看到结果表明也只生成了唯一的实例,这个简单的示例是自己对单例模式的一个学习认识的总结。文中讲述如有错误之处,欢迎大家批评指正。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是单例模式
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类保证这个类仅有一个实例,并提供一个访问它的全局访问点。
二、单例模式的优缺点及使用场景
可以看这篇文章,总结的挺全面:单例模式优缺点及应用场景
三、Qt中单例类的创建
1.config.h
#ifndef CONFIG_H
#define CONFIG_H
#include <QWidget>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>
namespace Ui {
class Config;
}
class Config : public QWidget
{
Q_OBJECT
public:
//explicit Config(QWidget *parent = nullptr);
~Config();
//提供一个公有的静态接口,获取该类的实例
static Config* getInstance();
private:
Ui::Config *ui;
//构造函数私有化,防止外界通过构造创建该类的实例
explicit Config(QWidget *parent = nullptr);
//添加私有静态指针变量指向该类的唯一实例
static Config* instance;
};
#endif // CONFIG_H
2.config.cpp
#include "config.h"
#include "ui_config.h"
//类外初始化
Config* Config::instance = nullptr;
QMutex mutex;
Config::Config(QWidget *parent) :
QWidget(parent),
ui(new Ui::Config)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_QuitOnClose,false); //设置随主窗口关闭而关闭
}
Config::~Config()
{
qDebug()<<"~ Config";
delete ui;
}
//加锁的懒汉式实现
Config* Config::getInstance()
{
//当多线程获取单例时有可能引发竞态条件
static QMutex mutex;
if(!instance)
{
QMutexLocker locker(&mutex); //加锁,解决线程安全的问题
if(!instance)
{
qDebug()<<"new Config";
instance = new Config; //注意内存泄露问题
}
}
return instance;
}
四、单例类的使用/测试
1.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "config.h" //包含单例类头文件即可通过接口获取实例
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pb_config_clicked();
void on_pb_config_1_clicked();
void on_pb_config_2_clicked();
private:
Ui::Widget *ui;
//Config* instance = nullptr;
};
#endif // WIDGET_H
2.widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//可以在主界面构造时来获取单例类的实例,配合析构
//instance = Config::getInstance();
}
Widget::~Widget()
{
//析构中将单例类实例进行delete,防止内存泄露
//if(instance)
//{
// delete instance;
//}
delete ui;
}
void Widget::on_pb_config_clicked()
{
//显示构造时创建的实例界面
//instance->show();
}
//获取了两次类的实例,却只有一次类的构造函数被调用,表明只生成了唯一实例
void Widget::on_pb_config_1_clicked()
{
Config* instance_1 = Config::getInstance();
instance_1->show();
}
void Widget::on_pb_config_2_clicked()
{
Config* instance_2 = Config::getInstance();
instance_2->show();
}
3.输出结果
界面上两个按钮分别点击,只会出现一个界面,查看打印输出处也只出现了一次"new Config",任意一个按钮点击出现界面后,另一个按钮点击无效果。
总结
其实目前的我对设计模式这方面还是不太了解的,所以还是需要加强学习的。软件的设计模式有很多,没必要为了设计模式而去写设计模式,主要看那些设计模式解决的问题是不是就是你遇到的问题呢?结合项目实际,选择你需要的。
本文讲述的单例设计模式,正如参考文章中所说:
You need to have one and only one object of a type in system
你需要系统中只有唯一一个实例存在的类的全局变量的时候才使用单例。
如果使用单例,应该用什么样子的?
越小越好,越简单越好,线程安全,内存不泄露。
hello:
共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。