设计模式之单例模式

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

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

总结

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值