1. 程式人生 > >可繼承擴充套件的單例實現

可繼承擴充套件的單例實現

最近在程式碼閱讀中看到了一種可繼承的單例實現,對使用者而言通過單例基類到定義的靜態介面獲取例項,而不必關心實際的單例實現。靈活性上,可通過繼承的重寫虛介面的方式實現單例功能的擴充套件。基礎程式碼如下:

/* 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. 單例中的定義的功能介面不易繼承擴充套件:例如在專案開發中錯誤資訊提示視窗統一在視窗右上角提示。實現上可通過定義訊息提示的單例物件,在程式出錯處呼叫單例物件的介面完成訊息提示。隨著功能的演進,又有了新的需求:訊息不僅要在視窗右上提示,部分錯誤要以彈模態框的方式提示。因例項唯一,在介面不動的情況下通過繼承的方式進行擴充套件顯然是做不到的,而且單例介面變動帶來的改動量也相當可觀。所以功能介面功能比較穩定可封裝為單例,如若不然就要為以後的功能變動買單。