可繼承擴充套件的單例實現
阿新 • • 發佈:2019-02-13
最近在程式碼閱讀中看到了一種可繼承的單例實現,對使用者而言通過單例基類到定義的靜態介面獲取例項,而不必關心實際的單例實現。靈活性上,可通過繼承的重寫虛介面的方式實現單例功能的擴充套件。基礎程式碼如下:
/* TestSingleton.h */
#include <iostream>
using namespace std;
#define ClassName(klass) (#klass)
class SingletonBase;
namespace
{
SingletonBase* ptr_single_instance = nullptr;
}
class SingletonBase
{
public :
SingletonBase();
~SingletonBase();
// 虛介面
virtual void TestSingleton();
static SingletonBase* Get();
};
SingletonBase::SingletonBase()
{
ptr_single_instance = this;
}
SingletonBase::~SingletonBase()
{
}
SingletonBase* SingletonBase::Get()
{
return ptr_single_instance;
}
void SingletonBase::TestSingleton()
{
cout << ClassName(SingletonBase) << std::endl;
}
class SingletonImp1 : public SingletonBase
{
public:
SingletonImp1();
~SingletonImp1();
virtual void TestSingleton() override;
};
SingletonImp1::SingletonImp1()
: SingletonBase()
{
}
SingletonImp1::~SingletonImp1()
{
}
void SingletonImp1::TestSingleton()
{
cout << ClassName(SingletonImp1) << std::endl;
}
void GoTest()
{
//使用者實際選擇建立何種單例,而不是在Get介面中new
SingletonImp1* ptr_single_imp = new SingletonImp1();
SingletonBase::Get()->TestSingleton();
}
當然在擴充套件性增強的同時也帶來問題:相對於傳統單例實現方式–在Get介面中new一個當前型別的例項,此種單例例項的建立暴露給了使用者,需要由使用者事先選擇並建立指定子型別的例項,然後其他地方獲取單例物件使用。
單例使用心得
單例便於單例型別中的介面呼叫,避免了型別上功能相互呼叫時引數傳遞的麻煩。但單例使用也存在一定的問題:
1. 單例的生命週期不易控制;
2. 單例使得型別間的依賴更加隱蔽且難以管理;
3. 單例中的定義的功能介面不易繼承擴充套件:例如在專案開發中錯誤資訊提示視窗統一在視窗右上角提示。實現上可通過定義訊息提示的單例物件,在程式出錯處呼叫單例物件的介面完成訊息提示。隨著功能的演進,又有了新的需求:訊息不僅要在視窗右上提示,部分錯誤要以彈模態框的方式提示。因例項唯一,在介面不動的情況下通過繼承的方式進行擴充套件顯然是做不到的,而且單例介面變動帶來的改動量也相當可觀。所以功能介面功能比較穩定可封裝為單例,如若不然就要為以後的功能變動買單。