【转载】C++11 改进我们的模式之改进单例模式

621 阅读2分钟

原文地址:(原创)C++11 改进我们的模式之改进单例模式

我对文章的格式和错别字进行了调整,并在他的基础上把重点部分进一步解释完善。以下是正文。

正文

我会写关于 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;