单例模式

单例模式

目的与概念

在开发中有时会需要确保系统中某一个类只有一个对象实例,并提供一个全局访问点以被所有模块共享,这应由对象提供者而不是使用者来保证;

例如:日志系统应只有一个,若有多个的话,可能会导致日志的混乱,而日志模块的提供者有责任约束其使用者,确保使用者的程序中只能有一个日志系统实例;

实现上述目的的方法就是单例模式。单例模式实际上是对唯一变量的一种封装,约束了其使用方式,让开发者更方便更安全地访问此变量;同时其可以让单例对象如同普通对象一样,作为参数在其他模块中使用,而其他模块不必知道其是否是单例;

单例模式恰当使用可以起到良好的效果,但是过度使用反而会阻碍程序的解耦,所以在实际使用中需要仔细考量;

根据单例对象构建的时机的不同,可将单例模式分为两种:

  • 懒汉方式,在首次使用时构建单例对象,即用时间换空间;
  • 饿汉方式,在程序启动时构建单例对象,即用空间换时间;

代码示例

懒汉方式与饿汉方式的代码描述如下所示:

  • 懒汉方式:
//  ----------------------------------------------------------------------------
/**
 * @file  Singleton.h
 */
// 本例中使用 Scott Meyers,《Effective C++》 中的 Singleton,这种方式在C++11之后保证线程安全。
class Singleton {
public:
	Singleton(const Singleton& rhs) = delete;
	Singleton& operator=(const Singleton& rhs) = delete;
    Singleton(Singleton&& rhs) = delete;
    Singleton& operator=(Singleton&& rhs) = delete;
    ~Singleton() {}
    
	static Singleton& getInstance() {
		static Singleton s_instance;
		return s_instance;
	}
private:
    Singleton() {}
    // 其他非静态成员变量
    // ...
};


//  ----------------------------------------------------------------------------
/**
 * @file  main.cpp
 */
// 调用代码
#include "Singleton.h"
int main()
{
    // 类型为引用
    Singleton & singleInst = Singleton::getInstance();
    // ...
    return 0;
}
  • 饿汉方式:
//  ----------------------------------------------------------------------------
/**
 * @file  Singleton.h
 */
// 此方式无需担心线程安全性问题,但是可能存在初始化顺序不确定问题
class Singleton {
public:
	Singleton(const Singleton& rhs) = delete;
	Singleton& operator=(const Singleton& rhs) = delete;
    Singleton(Singleton&& rhs) = delete;
    Singleton& operator=(Singleton&& rhs) = delete;
    ~Singleton() {}

	static Singleton& getInstance() {
		return s_instance;
	}
private:
    Singleton() {}
	static Singleton s_instance;
    // 其他非静态成员变量
    // ...
};
//  ----------------------------------------------------------------------------
/**
 * @file  Singleton.cpp
 */
// 静态变量类外初始化
#include "Singleton.h"
Singleton Singleton::s_instance = {};


//  ----------------------------------------------------------------------------
/**
 * @file  main.cpp
 */
// 调用代码
#include "Singleton.h"
int main()
{
    // 类型为引用
    Singleton & singleInst = Singleton::getInstance();
    // ...
    return 0;
}

Qt中的单例模式

单例模式使用十分广泛,例如 Qt 中 QCoreApplication 的实现也使用了单例模式,其代码片段如下:

//  ----------------------------------------------------------------------------
/**
 * @file  qapplication.h
 * @note  引自 Qt 库中的 include/QtCore/qapplication.h
 */
#if defined(qApp)
#undef qApp
#endif
#define qApp (static_cast<QApplication *>(QCoreApplication::instance()))
// ...


//  ----------------------------------------------------------------------------
/**
 * @file  qcoreapplication.h
 * @note  引自 Qt 库中的 include/QtCore/qcoreapplication.h
 */
class QCoreApplication {
    // ...
    static QCoreApplication *instance() { return self; }
    // ...
private:
    // ...
    static QCoreApplication *self;

    Q_DISABLE_COPY(QCoreApplication)
    // ...
};


//  ----------------------------------------------------------------------------
/**
 * @file  main.cpp
 */
// 调用代码
#include <QApplication>
#include <QString>
int main()
{
    // ...
    QString sheetStr = qApp->styleSheet();
    qDebug() << sheetStr;
    // ...
    
    return 0;
}

参考


本文作者: 王同学