序言
我本来我是没打算写多少设计模式的,毕竟我写得很简单,还是参考的菜鸟教程,但是竟然有人私信我想看剩下的,那好吧,确实,不会JAVA的看起来确实有点迷糊和难受(我也不会JAVA),会C++的还是看C++的方式来得舒服。
环境
Qt5.12 C++
理解
该图并不遵守UML规范,只是单纯为了便于源码快速回忆及理解
示例
饿汉式单例
饿汉式顾名思义就是担心饿死,提前把资源准备好,也就是一开始提前把实例申请好。
特点是:空间换时间
singleobject.h
#include <QSharedPointer>
class SingleObject
{
public:
/**
* @brief 获取唯一实例
* @return 返回指向唯一实例的指针
*/
static SingleObject *instance();
/**
* @brief 表示该类需要用到的函数
*/
void doSomething();
private:
/**
* @brief 单例模式时构造函数要放到私有中,防止被调用定义,以保证单例
*/
SingleObject();
// 保持实例的唯一性,使其无法复制和移动
Q_DISABLE_COPY_MOVE(SingleObject)
private:
static QSharedPointer< SingleObject> thisInstance;
};
.
singleobject.cpp
#include "singleobject.h"
static QSharedPointer< SingleObject> SingleObject::thisInstance{ new SingleObject};
SingleObject::SingleObject()
{
}
SingleObject *SingleObject::instance()
{
return thisInstance.data();
}
.
懒汉式 / 饱汉式 单例
懒汉式或者说饱汉式,顾名思义就是懒得弄,或者饱汉不需要准备,用到的时候再申请实例,但这样有些方式会线程不安全。
特点是:时间换空间
singleobject.h
#include <QDebug>
class SingleObject
{
public:
/**
* @brief 获取唯一实例
* @return 返回指向唯一实例的指针
*/
static SingleObject *instance();
/**
* @brief 表示该类需要用到的函数
*/
void doSomething();
private:
/**
* @brief 单例模式时构造函数要放到私有中,防止被调用定义,以保证单例
*/
SingleObject();
// 保持实例的唯一性,使其无法复制和移动
Q_DISABLE_COPY_MOVE(SingleObject)
private:
//方法一:只单线程使用时简便判断,会相对来说资源消耗小,但线程不安全,可以直接放cpp上边声明定义
static SingleObject *thisInstance;
//方法二:为多线程使用时加锁判断,会相对来说资源消耗较多,但线程安全,可以直接放cpp上边声明定义
static SingleObject *thisInstance;
static QMutex mutex;
};
#include "singleobject.h"
//方法一/方法二
SingleObject *SingleObject::thisInstance = nullptr;
SingleObject::SingleObject()
{
}
SingleObject *SingleObject::instance()
{
//方法一 线程不安全
if (nullptr == thisInstance)
{
//多个线程时,会存在A判断为空进来后,还没申请内存前,B也判断为空跟着进来,结果申请多了一次内存导致内存泄露
thisInstance = new SingleObject;
}
return thisInstance;
//方法二 线程安全
if (nullptr == thisInstance)
{
QMutexLocker locker(&mutex);
//多个线程时A线程来到这里,B虽然跟着进来了,但是A上锁了,B只能等,A申请好内存出去后B再进来判就不会空了,也就出去了,不会再次申请内存。
if (nullptr == thisInstance)
thisInstance = new SingleObject;
}
return thisInstance;
//方法三:最推荐的单例方式,在C++中最为简便JAVA没法这样做的,线程安全
static SingleObject thisInstance;
return &thisInstance;
//方法四:也可以这样用,和方法三区别不太大,消耗也是多一份智能指针,但是资源消耗放在堆上,也可以用普通的指针,只要你自行有地方释放即可
static QScopedPointer< SingleObject > thisInstance(new SingleObject);
return thisInstance.data();
}
.
调用的地方
SingleObject::instance()->doSomething();
.
个人小技巧
分享个人一个常使用的小技巧,有些类+实例函数调用很长,我会用宏去替换,这样就可以简短使用
singleobject.h
#define SinObj SingleObject::instance()
...
调用处:
SinObj->doSomething();