知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!
设计模式概念
设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,与我们自己摸索出来的问题解决之道相比较,有以下优点可取:
- 代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好
- 当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够做到软件设计要求的“开-闭原则”,即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活
- 合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的根本原则“高内聚,低耦合”
单例模式概念
单例模式(Singleton Pattern)是最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。
设计一个单例就必须要满足下面三个条件:
- 构造函数私有化,这样用户就不能任意定义该类型的对象了
- 定义该类型唯一的对象
- 通过一个static静态成员方法返回唯一的对象实例
优点:
- 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
- 2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
- 1、要求生产唯一序列号。
- 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
单例模式的几种实现方式
1.饿汉单例模式,线程安全
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
class CSingleton
{
public:
static CSingleton* getInstance()
{
return &single;
}
private:
static CSingleton single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl; }
CSingleton(const CSingleton&); // 防止外部使用拷贝构造产生新的对象,如下面CSingleton s = *p1;
};
CSingleton CSingleton::single;
int main()
{
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout<<p1<<" "<<p2<<" "<<p3<<endl;
return 0;
}
2.懒汉单例模式,线程不安全
class CSingleton
{
public:
static CSingleton* getInstance()
{
if (nullptr == single)
{
single = new CSingleton();
}
return single;
}
private:
static CSingleton *single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl; }
CSingleton(const CSingleton&);
};
CSingleton* CSingleton::single = nullptr;
int main()
{
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout << p1 << " " << p2 << " " << p3 << endl;
return 0;
}
3.懒汉单例模式,线程安全
#include <iostream>
#include <pthread.h>
using namespace std;
class CSingleton
{
public:
static CSingleton* getInstance()
{
// 获取互斥锁
pthread_mutex_lock(&mutex);
if (nullptr == single)
{
single = new CSingleton();
}
// 释放互斥锁
pthread_mutex_unlock(&mutex);
return single;
}
private:
static CSingleton *single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton()
{
pthread_mutex_destroy(&mutex); // 释放锁
cout << "~CSingleton()" << endl;
}
CSingleton(const CSingleton&);
class CRelease
{
public:
~CRelease() { delete single; }
};
static CRelease release;
// 定义线程间的互斥锁
static pthread_mutex_t mutex;
};
CSingleton* CSingleton::single = nullptr;
CSingleton::CRelease CSingleton::release;
// 互斥锁的初始化
pthread_mutex_t CSingleton::mutex = PTHREAD_MUTEX_INITIALIZER;
int main()
{
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
return 0;
}
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁才能保证单例,但加锁会影响效率。
这种方式采用双重校验锁,安全且在多线程情况下能保持高性能。