设计模式之单例模式

来源:互联网 发布:sketchup mac版界面 编辑:程序博客网 时间:2024/06/05 16:22

在上篇博文中,我们分析了适配器模式,适配器模式通俗地来讲就是实现了接口之间的转换,是之前不能够使用的接口能够在新的环境下使用,今天我们要学习的是另外一个设计模式——单例模式,说到单例模式想必大家都应该明白,通俗地说就是只能产生一个对象的类,个人认为这种设计模式在整个设计模式中都是最简单的,并且这种模式最大的好处就是对象易于管理,这种模式在我的工作中也是时常看到,下面我们就来看看这个单例模式,代码如下:

#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;};#endifinclude "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的方式,则不会,好好地体会下

总结

       本篇博文主要分析了下单例模式,这个模式在实际应用中很广泛,在我的工作中经常看到,这个模式也是最简单的,但是如何灵活地运用,这个只有在实际开发中,好好地体会了,在单例模式中,我们会很在意在多线程环境下的单例模式安全性问题,确实,在实际的开发中,由于只有一个对象,因此如何在线程间安全地访问这个对象,将会成为开发中涉及到单例时不可不考虑的问题,其实如果简单的程序应用,完全可以采用加大锁的方式,如果涉及到一些对实时性要求较高的场所,可以尝试一些比较精确的分块加锁的机制,在这里就不讨论了,好了,本篇博文到此结束,下篇我们继续分析设计模式之——原型模式。

如果需要,请注明转载,多谢

5 0
原创粉丝点击