设计模式之单例模式
2014-02-24 16:37
134 查看
在上篇博文中,我们分析了适配器模式,适配器模式通俗地来讲就是实现了接口之间的转换,是之前不能够使用的接口能够在新的环境下使用,今天我们要学习的是另外一个设计模式——单例模式,说到单例模式想必大家都应该明白,通俗地说就是只能产生一个对象的类,个人认为这种设计模式在整个设计模式中都是最简单的,并且这种模式最大的好处就是对象易于管理,这种模式在我的工作中也是时常看到,下面我们就来看看这个单例模式,代码如下:
测试代码:
测试结果:
book:C++ 20
依据单例模式的定义:只有一个对象的类,上述代码中实现了这种方式,即将构造函数设置为私有的,并且只提供一个访问对象的接口,在上述代码中通过采用shared_ptr智能指针可以防止内存泄露问题,这种写法相比传统的方式应该要安全点,但是其所凸显的问题依然存在,即在多线程的环境中,同样有不安全的问题,下面我们就来改进下上述的实现方法,使其在多线程环境下也能够正常工作,代码如下:
测试结果:
book:Python price:60
4
book:Java price:40
3
book:C++ price:20
2
上述代码已经对对象进行了加锁处理,这种方式也被称为“DOUBLE CHECK”,就是在创建对象时,对象被检查了两次,这两次都是有必要的,可能会有人说直接将mut放到函数开头不就行了,也没必要搞DOUBLE CHECK,在线程不多时,这种方式可能会有作用,但是当线程数量巨大时,这种方式会严重影响到系统系能,这个可以通过实验来分析,主要是因为线程每次访问对象时,都需要获取锁,而采用double check的方式,则不会,好好地体会下
总结
本篇博文主要分析了下单例模式,这个模式在实际应用中很广泛,在我的工作中经常看到,这个模式也是最简单的,但是如何灵活地运用,这个只有在实际开发中,好好地体会了,在单例模式中,我们会很在意在多线程环境下的单例模式安全性问题,确实,在实际的开发中,由于只有一个对象,因此如何在线程间安全地访问这个对象,将会成为开发中涉及到单例时不可不考虑的问题,其实如果简单的程序应用,完全可以采用加大锁的方式,如果涉及到一些对实时性要求较高的场所,可以尝试一些比较精确的分块加锁的机制,在这里就不讨论了,好了,本篇博文到此结束,下篇我们继续分析设计模式之——原型模式。
如果需要,请注明转载,多谢
#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的方式,则不会,好好地体会下
总结
本篇博文主要分析了下单例模式,这个模式在实际应用中很广泛,在我的工作中经常看到,这个模式也是最简单的,但是如何灵活地运用,这个只有在实际开发中,好好地体会了,在单例模式中,我们会很在意在多线程环境下的单例模式安全性问题,确实,在实际的开发中,由于只有一个对象,因此如何在线程间安全地访问这个对象,将会成为开发中涉及到单例时不可不考虑的问题,其实如果简单的程序应用,完全可以采用加大锁的方式,如果涉及到一些对实时性要求较高的场所,可以尝试一些比较精确的分块加锁的机制,在这里就不讨论了,好了,本篇博文到此结束,下篇我们继续分析设计模式之——原型模式。
如果需要,请注明转载,多谢
相关文章推荐
- 一句话概括设计模式
- 关于工厂和dao(j2ee设计模式和GOF的设计模式)
- javascript 设计模式
- 【设计模式】为别人做嫁衣 --- 代理模式
- 设计模式六大原则(1):单一职责原则
- Java设计模式之面向对象设计原则
- Java I/O 技术(四)—— 装饰设计模式及应用 初识
- 设计模式六大原则
- 设计模式学习笔记之迭代器模式
- 设计模式之结构型设计模式
- 设计模式 抽象工厂模式
- Java设计模式 —— 原型模式(Proto Type)
- C#设计模式学习笔记-单例模式
- 二十三、 桥接设计模式
- Android设计模式源码解析之外观模式(Facade)
- php 设计模式
- 设计模式之桥接模式
- 设计模式C#描述——单例与多例模式
- 设计模式之Observer
- PHP设计模式中之装饰模式