C++面试宝典设计模式篇之单例模式
文章目录
前言
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。设计模式是面试热门考点,掌握设计模式可以让你深入理解面向对象思想,使设计方案更加灵活,方便后期维护修改。
一、设计模式之单例模式
二、单例模式详细介绍
2.1单例模式概念介绍
单例模式属于创建型模式,这种模式涉及到一种单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式。
单例类的特征: 1.单例类最多只能有一个实例;
2.单例类必须自己创建自己唯一的实例;
3.单例类必须给所有其他的对象提供这一实例。
2.2使用单例模式的目的和优缺点
目的:使用单例类是为了保证某一个类仅有一个实例,并提供一个访问它的全局访问点。
单例类主要解决了一个全局使用的类的频繁的创建与销毁。
所以单例模式有以下几个优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的 创建和销毁实例; 2、避免对资源的多重占用。
缺点:单例模式有一个不好的地方就是:单例类没有接口,不能继承。
2.3单例模式的使用场景
当我们想在程序中控制实例数目,节约系统资源的时候,就可以考虑使用单例类。
例如:1.频繁创建及销毁的对象,例如工具类;
2.不变的对象;
3.设备管理器,系统中可能有多个设备,但是只有一个设备管理器,用于管理设备驱动;
4.数据池,用来缓存数据的数据结构,需要在一处写,多处读取或者多处写,多处读取;
5.打印机,日志对象;
2.4单例模式的定义方式
定义一个单例类:
(1)私有化构造函数,以防止外界创建单例类的对象。
private Singleton()
不需用拷贝和赋值,在单例模式中,始终只有一个对象
(2)使用类的私有静态指针,变量指向类的唯一实例。(提供一个自身的静态私有成员变量,以指向类的实例;
private static Singleton * uniqueInstance()
(3)使用一个公有的静态方法获取该实例。
public static Singleton * getInstance()
2.5单例模式的实现方式
懒汉式:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化。与之对应的是饿汉式单例。(注意,懒汉本身是线程不安全的)
饿汉式:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。(本身就是线程安全的)
那如何选择懒汉和饿汉模式呢?
特点与选择:
懒汉:直接创建出类的实例化 因为上来就实例化一个对象,占用了内存,并不管主程序是否用到该类。在访问量较小时,采用懒汉实现。这是以时间换空间。
饿汉:由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
三、单例模式代码示例
3.1懒汉式代码示例
/*懒汉式单例模式*/
class Singleton_lazy{
private:
/*构造函数私有化,保证不在类的外部实例化*/
Singleton_lazy(){cout<<"我是懒汉式构造函数"<<endl;}
public:
/*用户接口,在使用的时候创建一个类的实例化*/
static Singleton_lazy* getInstance(){
//判断pSingleton是否为NULL,如果为NULL,即判定需要实例化
if (pSingleton==NULL){
pSingleton=new Singleton_lazy;
}
return pSingleton;
}
private:
static Singleton_lazy* pSingleton; //静态类对象
};
//静态对象类外初始化
Singleton_lazy* Singleton_lazy::pSingleton=NULL;
3.2饿汉式代码示例
/*饿汉式单例模式*/
class Singleton_hungry{
private:
Singleton_hungry(){cout<<"我是饿汉式构造函数"<<endl;}
public:
/*返回已经创建好的类实例*/
static Singleton_hungry* getInstance(){
return pSingleton;
}
private:
static Singleton_hungry* pSingleton;
};
//类外初始化:直接创建出类的实例
Singleton_hungry* Singleton_hungry::pSingleton=new Singleton_hungry;
如果想懒汉模式实现线程安全,则应该加锁
3.3线程安全的懒汉式代码示例
#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
class Cperson
{
private:
Cperson(){}
~Cperson(){}
private:
static Cperson* ps;
static pthread_mutex_t mutex;
public:
static Cperson* GetObject();
static void Destory(Cperson* p);
};
Cperson* Cperson::ps = 0;
pthread_mutex_t Cperson::mutex = PTHREAD_MUTEX_INITIALIZER;
Cperson* Cperson::GetObject()
{
if(ps == 0)
{
pthread_mutex_lock(&mutex);
if(ps == 0)
ps = new Cperson;
pthread_mutex_unlock(&mutex);
}
return ps;
}
void Cperson::Destory(Cperson* p)
{
if(p->ps)
{
delete p->ps;
p->ps == NULL;
}
pthread_mutex_destroy(&(p->mutex));
}
Cperson* p2;
void* work(void *arg)
{
p2 = Cperson::GetObject();
cout<<"work:"<<p2<<endl;
}
int main()
{
pthread_t tid = 0;
pthread_create(&tid,NULL,work,NULL);
//Cperson* p2 = Cperson::GetObject();
Cperson* p1 = Cperson::GetObject();
sleep(1);//防止主函数执行过快 线程函数还没来得及执行
cout<<"p1:"<<p1<<endl;
cout<<"p2:"<<p2<<endl;
Cperson::Destory(p1);
return 0;
}
四、总结
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的的充分理解。
正确使用设计模式有很多优点:
1.可以提高程序员的思维能力、编程能力和设计能力。
2.使面试程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
3.使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
今天博主分享的单例模式只是设计模式的一种,能在适当的场景使用合理的设计模式对于程序员的成长至关重要,后续博主会继续分享设计模式的学习经验。
每日一语:虽然坚持自己的理想很难,但无论最后有没有实现都好,那种执着与信念,将是一生的财富,与大家共勉!