我对文章的格式和错别字进行了调整,并在他的基础上把重点部分进一步解释完善。以下是正文。
正文
我会写关于 C++11 的一个系列的文章,会讲到如何使用 C++11 改进我们的程序,本次讲如何改进我们的模式,会讲到如何改进单例模式、观察者模式、访问者模式、工厂模式、命令模式等模式。通过 C++11 的改进,我们的模式变得更通用、更简洁、更强大。本次讲如何改进单例模式。
传统单例类的问题
在 C++11 之前,我们写单例模式的时候会遇到一个问题,就是多种类型的单例可能需要创建不同类型的单例类,主要是因为创建单例对象的构造函数无法统一,各个类型的形参不尽相同,导致我们不容易做一个所有类型都通用的单例。现在 C++11 帮助我们解决了这个问题,解决这个问题靠的是 C++11 的可变参数模板函数。直接看代码。
template <typename T>
class Singleton
{
public:
/// @note 初始化单例,可变参模板函数
template<typename... Args>
static T* Instance(Args&&... args) ///< 注意是右值引用
{
if(m_pInstance == nullptr)
m_pInstance = new T(std::forward<Args>(args)...); ///< 任意类型、不同形参的单例构造,注意完美转发的可变参数
return m_pInstance;
}
/// @note 返回单例
static T* GetInstance()
{
if (m_pInstance == nullptr)
throw std::logic_error("the instance is not init, please initialize the instance first");
return m_pInstance;
}
/// @note 销毁单例
static void DestroyInstance()
{
delete m_pInstance;
m_pInstance = nullptr;
}
private:
/// @note 禁用以下函数
Singleton(void);
virtual ~Singleton(void);
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
private:
/// @note 禁直接获取该单例
static T* m_pInstance;
};
/// @note 模板类静态成员变量初始化
template <class T>
T* Singleton<T>::m_pInstance = nullptr;
这个单例模式可以解决不同类型构造函数形参不尽相同的问题,真正意义上对所有类型都通用的单例模式。
更新说明
由于原来的接口中,单例对象的初始化和取值都是一个接口,可能会遭到误用,更新之后,讲初始化和取值分为两个接口,单例的用法为:先初始化,后面取值,如果中途销毁单例的话,需要重新初始化并取值。如果没有初始化就取值则会抛出一个异常。
引申出的示例
增加 Multiton 类的实现,该类是通过键值对 map 来保存 Multiton 的不同键值的多个实例。
#include <map>
#include <string>
#include <memory>
using namespace std;
template < typename T, typename K = string> ///< K 表示 map 的键值类型
class Multiton
{
public:
/// @note 键值为左值
template<typename... Args>
static std::shared_ptr<T> Instance(const K& key, Args&&... args)
{
return GetInstance(key, std::forward<Args>(args)...);
}
/// @note 键值为右值
template<typename... Args>
static std::shared_ptr<T> Instance(K&& key, Args&&... args)
{
return GetInstance(key, std::forward<Args>(args)...);
}
private:
template<typename Key, typename... Args>
static std::shared_ptr<T> GetInstance(Key&& key, Args&&...args)
{
std::shared_ptr<T> instance = nullptr;
auto it = m_map.find(key); ///< 查看该实例是否已经存在于 map 当中
if (it == m_map.end()) ///< 不存在则构造,则依据指定键值保存到 map 中
{
instance = std::make_shared<T>(std::forward<Args>(args)...);
m_map.emplace(key, instance);
}
else ///< 存在则直接取出
{
instance = it->second;
}
return instance;
}
private:
Multiton(void);
virtual ~Multiton(void);
Multiton(const Multiton&);
Multiton& operator = (const Multiton&);
private:
/// @note 存储实例指针的 map
static map<K, std::shared_ptr<T>> m_map;
};
template <typename T, typename K>
map<K, std::shared_ptr<T>> Multiton<T, K>::m_map;