設計模式--單例模式Singleton(創建型)

單例模式Singleton背景

軟件實現中,有些時候整個系統只需要擁有一個全局對象,這樣有利於協調系統的整體行爲,使系統在單個對象存在時更有效率,或者限制實例化爲特定數量的對象。例如對某個協議棧模塊的訪問, 需要整個模塊有且僅有一個訪問入口,否則將會導致協議棧狀態混亂,爲此需要實現創建管理一個全局管理對象,維持其生命週期。

在軟件工程中,單例模式提供了這樣一個實現,保證了一個類只有一個實例存在,並提供一個訪問它的全局訪問點。

通過情況下,我們可以使用全局變量使得一個對象被全局訪問,但該方法不能防止實例化多個對象,無法保證實例唯一性,一個最好的辦法是,讓類自身負責保護它的唯一實例,這個類可以保證沒有其它實例被創建,並且提供一個訪問該實例的方法,實現類實例的唯一性和受控訪問。

單例模式Singleton實現

單例模式一個經典的實現方式:

class Singleton  
{  
private:  
    Singleton(){
        //private constructor, 阻止外部調用new對象 
    }                      
    Singleton(const Singleton&){ 
        //private copy constructor, 防止被複制
    };     
    Singleton& operator=(const Singleton&){ 
        //private operator =, 防止被複制
    }; 

private: 
    static Singleton *m_pInstance;      

public:  
    static Singleton* GetInstance()  //本類實例全局唯一訪問點
    {  
        if(NULL == m_pInstance)    
            m_pInstance = new Singleton();

        return m_pInstance;  
    }

    static void DestoryInstance()
    {
        if (m_pInstance != NULL )
        {
            delete m_pInstance;
            m_pInstance = NULL ;
        }
    } 

    // Other methods...
};  

Singleton class通過將類的構造函數、複製構造函數以及賦值函數限定爲private,避免了類在外部被實例化,其唯一實例只能通過GetInstance()方法訪問。

多線程環境單例模式Singleton

上述單例模式實現代碼直觀易懂,但沒有考慮線程安全問題,在多線程的運行環境中,當多個線程同時訪問Singletion類的GetInstance()方法時,極有可能造成創建多個實例。若線程A運行檢測到m_pInstance == NULL, 但來得及執行m_pInstance = new Singleton()時被線程B中斷,線程B 執行同樣的判斷m_pInstance == NULL 從而創建了類的實例,當線程A再次獲得運行權時,將繼續執行創建類實例的操作,再次創建了實例,從而創建了多個實例,違背單例模式的初衷。因此比較直接的做法是,在創建實例時加鎖lock,lock 確保當線程A位於代碼lock保護區域時,其餘線程不能進入該lock保護區域,此時若其它線程試圖進入lock 保護區域,那麼它將一直被阻塞等待,直到鎖對象被釋放。

static Singleton* GetInstance()  //本類實例全局唯一訪問點
{  
    lock();   //TODO: 借用其它類來實現, std::mutex
    {
        if(NULL == m_pInstance)    
            m_pInstance = new Singleton();
    }         

    return m_pInstance;  
} 

這種實現方式的確保證了單例模式的線程安全,確保對象創建的唯一性,但每次調用GetInstance 獲取對象都需要lock 後判斷, 對性能有較大影響, 一種改進的做法是,先判斷對象是否已經創建,在未創建的情況下再加鎖創建, 確保創建的唯一性。

static Singleton GetInstance() //本類實例全局唯一訪問點
{  

    if(NULL == m_pInstance)
    {
        lock(); //TODO: 借用其它類來實現, std::mutex
        {
            if(null == m_pInstance)
                m_pInstance = new Singleton();
        }
    }

    return m_pInstance;
}

這種方式實現了在每次訪問GetInstance 時僅僅在對象不存在時需要加鎖lock,大大提高了效率。

說明: 單例模式有多種實現方式,文中只實現了其中的一種,逐步分析提供了在多線程環境中的安全機制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章