QT下单例模式

1 优点

  1. 提供了对唯一实例的受控访问。
  2. 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
  3. 允许可变数目的实例。

2 缺点

  1. 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
  2. 单例类的职责过重,在一定程度上违背了“单一职责原则”。
  3. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
  4. 对象生命周期。单例模式没有提出对象的销毁,在提供内存的管理的开发语言中,只有单例模式对象自己才能将对象实例销毁,因为只有它拥有对实例的引用。在各种开发语言中,比如C++,其他类可以销毁对象实例,但是这么做将导致单例类内部的指针指向不明。

3 代码示例

懒汉模式:

class LogMannage
{
public:
    static LogMannage* instance();	//通过该接口访问
    void A();
private:
    static LogMannage *myLog;       //单例模式定义的指针
    LogMannage();	//构造函数需要私有化,不能被外部new
    ~LogMannage();
};

//懒汉模式,静态变量初始化为空
LogMannage* LogMannage::myLog = NULL;  

LogMannage *LogMannage::instance()	//接口返回类指针,如果指针为空则需要创建对象再返回对象指针(第一次调用)
{
    if(myLog == NULL)     //如果要考虑到线程安全则需要添加互斥锁
            mPtr = new ThreadWifiBase();
    return mPtr;
}

饿汉模式:

class LogMannage
{
public:
    static LogMannage* instance();	//通过该接口访问
    void A();
private:
    static LogMannage *myLog;       //单例模式定义的指针
    LogMannage();	//构造函数需要私有化,不能被外部new
    ~LogMannage();
};

//饿汉模式,静态变量初始化的时候即创建对象
LogMannage* LogMannage::myLog = new LogMannage();  

LogMannage *LogMannage::instance()	//接口返回类指针就行(饿汉模式指针初始化时就创建了)
{
    return myLog;
}

4 单例模式实现原理

1.1 私有化构造函数,使得外界不能通过new方式创建该单例对象。
1.2 创建静态对象指针。

1.1、1.2操作代码如下所示:

class RaspiTemp
{
private:
    static RaspiTemp *instancePrt;	//创建静态对象指针
    explicit RaspiTemp();		//私有化构造函数
    ~RaspiTemp();
}
1.3 单例对象访问接口定义:

需要定义为静态函数,可供外部直接访问而不需要依据对象指针访问。代码如下:

publicstatic RaspiTemp* instance();	//定义
1.3 单例对象的创建

懒汉模式是在需要用的时候,即首次访问时才创建单例对象,所以首次访问相对比较慢。懒汉模式就好像一个懒人(狠人),一直懒得找对象,在需要结婚的时候才去找对象,有了对象后就结婚;而对应的饿汉就是,管他结婚不结婚,先找个对象再说,需要结婚的时候直接结就行了。

饿汉模式是在程序启动,静态变量(1.2中单例对象类的静态指针)初始化的时候就创建单例对象。由于静态变量初始化在代码导入内存时候就初始化了,即main函数运行之前就创建了单例对象,所以不存在线程安全问题。

1.3.1 懒汉模式实现

代码如下:

// .cpp文件中实现	
RaspiTemp *RaspiTemp::instancePrt = NULL;			
RaspiTemp*RaspiTemp::instance()		//实现
{
    if(instancePrt== NULL)    
            instancePrt= new RaspiTemp();	//懒汉模式下对象创建(首次调用instance时创建)
    return instancePrt;
}
1.3.1 饿汉模式实现

代码如下:

// .cpp文件中实现	
RaspiTemp *RaspiTemp::instancePrt = new RaspiTemp();	//饿汉模式下对象创建(静态变量初始化时创建)
RaspiTemp*RaspiTemp::instance()		//实现
{
    return instancePrt;
}

5 单例模式的线程安全实现

前面有说明,饿汉模式在静态变量初始化的时候就实例化了单例对象,所以不存在线程安全问题,而且其访问接口中只有返回对象指针而没有创建对象的代码。但是单例模式对象的创建是在首次访问的时候,如果两个线程同时访问的时候,就可能造成单例对象被重复构建而导致内存浪费(对!仅仅内存浪费而已),解决此方法就是使用互斥锁。

为了理解,还是使用之前例子说明一下,结婚前才找对象,其实就是相亲,在你没相亲成功前你就是单身状态,你可以同时相亲两个或多个妹子(帅哥),不巧结果全相中了,这时候你的对象就有了多个,而结婚的对象确只能一个(别问我为什么,我也不知道),于是其他对象就被放弃在那里;然后政府为了避免这种浪费可耻的现象,于是规定你在同一时刻只能相亲一个对象,这个对象相亲结束后才能相亲下一个,这样就能解决问题了不是,但是怎么做到呢?这就是需要上锁,首先判断指针是否为空(指向对象),如果为空就加锁,然后再判断一次后再创建对象。

懒汉模式中代码修改如下:

static QMutex staticMutexSend;
RaspiTemp *RaspiTemp::instance()
{
    if(instancePrt == NULL)     
    {
    	staticMutexSend.lock();	//保证线程安全
        if(instancePrt == NULL)
            instancePrt = new RaspiTemp ();
        staticMutexSend.unlock();		
    }
    return instancePrt ;
}

6 单例模式+独立子线程模式

多线程的实现,qt有两种方式,一种是继承Qthread类并重写run() 函数实现;一种是继承QObject类,使用QObject中的moveToThread() 函数实现。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值