設計模式之單例模式

在上篇博文中,我們分析了適配器模式,適配器模式通俗地來講就是實現了接口之間的轉換,是之前不能夠使用的接口能夠在新的環境下使用,今天我們要學習的是另外一個設計模式——單例模式,說到單例模式想必大家都應該明白,通俗地說就是隻能產生一個對象的類,個人認爲這種設計模式在整個設計模式中都是最簡單的,並且這種模式最大的好處就是對象易於管理,這種模式在我的工作中也是時常看到,下面我們就來看看這個單例模式,代碼如下:

#ifndef __SINGLETON__H
#define __SINGLETON__H

#include <iostream>
#include <string>
#include <boost/smart_ptr.hpp>
using namespace std;
using namespace boost;


class Book
{
    public:
        Book(string  bookName = string(),const int price = 0):bookName(bookName),price(price)
        {
        }
        ~Book(){}

        void setBookName(string  bookName)
        {
            this->bookName = bookName;
        }
        void setPrice(const int price)
        {
            this->price = price;
        }
        void display()
        {
            cout<<"book:"<<bookName<<" "<<price<<endl;
        }
    private:
        string bookName;
        int price;
};
template<class T>
class Singleton
{
    public:
        static shared_ptr<T> getSingleton()
        {
            if(object.use_count() == 0)
                object = shared_ptr<T>(new T());
            return object;
        }
    private:
        Singleton(){}
    private:
        static shared_ptr<T> object;
};
template<class T>
shared_ptr<T> Singleton<T>::object;
#endif

測試代碼:

#include "Singleton.h"


int main()
{
    shared_ptr<Book> book =Singleton<Book>::getSingleton();
    book->setBookName("C++");
    book->setPrice(20);

    shared_ptr<Book> book1 = Singleton<Book>::getSingleton();
    book1->display();
    return 0;
}

測試結果:

book:C++ 20


依據單例模式的定義:只有一個對象的類,上述代碼中實現了這種方式,即將構造函數設置爲私有的,並且只提供一個訪問對象的接口,在上述代碼中通過採用shared_ptr智能指針可以防止內存泄露問題,這種寫法相比傳統的方式應該要安全點,但是其所凸顯的問題依然存在,即在多線程的環境中,同樣有不安全的問題,下面我們就來改進下上述的實現方法,使其在多線程環境下也能夠正常工作,代碼如下:

#ifndef __SINGLETON__H
#define __SINGLETON__H

#include <iostream>
#include <string>
#include <boost/smart_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;

boost::mutex mut;
class Book
{
    public:
        Book(string  bookName = string(),const int price = 0):bookName(bookName),price(price)
        {
        }
        ~Book(){}

        void setBookName(string  bookName)
        {
            mut.lock();
            this->bookName = bookName;
            mut.unlock();
        }
        void setPrice(const int price)
        {
            mut.lock();
            this->price = price;
            mut.unlock();
        }
        void display()
        {
            mut.lock();
            cout<<"book:"<<bookName<<" "<<"price:"<<price<<endl;
            mut.unlock();
        }
    private:
        string bookName;
        int price;
};
template<class T>
class Singleton
{
    public:
        static shared_ptr<T> getSingleton()
        {
            if(object.use_count() == 0)
            {
                mut.lock();
                if(object.use_count()==0)
                    object = shared_ptr<T>(new T());
                mut.unlock();
            }
            return object;
        }
        static int use_count()
        {
            return object.use_count();
        }
    private:
        Singleton(){}
    private:
        static shared_ptr<T> object;
};
template<class T>
shared_ptr<T> Singleton<T>::object;
class task
{
    public:
        task(string bookName = string(),const int price = 0):bookName(bookName),price(price){}
        ~task(){}
        task(const task& tsk)
        {
            bookName = tsk.bookName;
            price = tsk.price;
        }
        task& operator = (const task& tsk)
        {
            bookName = tsk.bookName;
            price = tsk.price;
        }
        void operator()()const
        {
            Singleton<Book>::getSingleton()->setBookName(bookName);
            Singleton<Book>::getSingleton()->setPrice(price);
            Singleton<Book>::getSingleton()->display();
            cout<<Singleton<Book>::getSingleton().use_count()<<endl;
        }
    private:
        string bookName;
        int price;
};
#endif

include "Singleton.h"


int main()
{
    boost::thread thr1(task("C++",20));
    boost::thread thr2(task("Java",40));
    boost::thread thr3(task("Python",60));

    thr1.join();
    thr2.join();
    thr3.join();
    return 0;
}

測試結果:

book:Python price:60
4
book:Java price:40
3
book:C++ price:20
2
上述代碼已經對對象進行了加鎖處理,這種方式也被稱爲“DOUBLE CHECK”,就是在創建對象時,對象被檢查了兩次,這兩次都是有必要的,可能會有人說直接將mut放到函數開頭不就行了,也沒必要搞DOUBLE CHECK,在線程不多時,這種方式可能會有作用,但是當線程數量巨大時,這種方式會嚴重影響到系統系能,這個可以通過實驗來分析,主要是因爲線程每次訪問對象時,都需要獲取鎖,而採用double check的方式,則不會,好好地體會下

總結

       本篇博文主要分析了下單例模式,這個模式在實際應用中很廣泛,在我的工作中經常看到,這個模式也是最簡單的,但是如何靈活地運用,這個只有在實際開發中,好好地體會了,在單例模式中,我們會很在意在多線程環境下的單例模式安全性問題,確實,在實際的開發中,由於只有一個對象,因此如何在線程間安全地訪問這個對象,將會成爲開發中涉及到單例時不可不考慮的問題,其實如果簡單的程序應用,完全可以採用加大鎖的方式,如果涉及到一些對實時性要求較高的場所,可以嘗試一些比較精確的分塊加鎖的機制,在這裏就不討論了,好了,本篇博文到此結束,下篇我們繼續分析設計模式之——原型模式。

如果需要,請註明轉載,多謝

發佈了52 篇原創文章 · 獲贊 10 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章