创建型模式:提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象
确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的 *** 作都只能基于这个唯一实例
比如日志模块,数据库模块,任务管理器
饿汉式单例模式
- 还没有获取实例对象,实例对象就已经产生了,饿汉式是线程安全的
- 优点:程序加载时就进行实例化,之后的 *** 作效率会很高。
- 缺点: 由于程序加载时就进行实例化,如果后续不对此类进行任何 *** 作,就会导致内存的浪费
//饿汉式单例:没调用获取单例对象的接口,单例对象就已经产生了
class Singleton
{
public:
static Singleton* getInstance() //3 定义获取唯一实例的接口方法
{
return &instance;
}
private:
static Singleton instance; //2 定义一个唯一的类的实例对象
private:
Singleton() {} //1 构造函数私有化
Singleton(const Singleton&) = delete; //1 删除拷贝构造
Singleton& operator=(const Singleton&) = delete;//1 删除赋值重载
};
Singleton Singleton::instance; //类的static成员要在类外初始化,不赋初值则为编译器默认值
static成员要在类外初始化。
为什么?
因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。
懒汉式单例模式
- 直到第一次获取唯一实例的时候,才产生实例
- 优点: 在第一次调用的时候才进行实例化。
- 缺点: 当多个线程同时进入到 if(instance == nullptr) {…} 时,会创建多个对象。
//懒汉式单例,将对象的实例化延迟到第一次调用的时候
class Singleton
{
public:
static Singleton* getInstance() //3 定义获取唯一实例的接口方法
{
if(instance == nullptr)
{
instance = new Singleton();
}
return instance;
}
private:
static Singleton *instance; //2 定义一个唯一的类的实例对象
private:
Singleton() {} //1 构造函数私有化
Singleton(const Singleton&) = delete; //1 删除拷贝构造
Singleton& operator=(const Singleton&) = delete;//1 删除赋值重载
};
Singleton* Singleton::instance = nullptr;
加互斥量,保证getInstance多线程环境是安全的
//线程安全的懒汉式单例
std::mutex mtx;//*****
class Singleton
{
public:
static Singleton* getInstance()
{
if(instance == nullptr)
{
lock_guard<std::mutex> guard(mtx);//*****锁加双重判断,锁放这是让锁粒度小一点
if(instance == nullptr)
{
instance = new Singleton();
}
}
return instance;
}
private:
static Singleton *volatile instance; //volatile告诉编译器instance是要每次在内存中读取的,不要优化到去缓存中读取
private:
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
Singleton*volatile Singleton::instance = nullptr;
懒汉式单例代码2:
//线程安全的懒汉式单例
std::mutex mtx;//*****
class Singleton
{
public:
static Singleton* getInstance()
{
//线程安全的,函数静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令了
static Singleton instance;
return &instance;
}
private:
Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
观察者模式(行为型)
行为型模式主要关注的是对象之间的通信
观察者模式别名:发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式
主要关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其他对象都能够接收到相应的通知
例如:通过一组数据(数据对象)可以绘制曲线图(对象1)、柱状图(对象2)、圆饼图(对象3),当数据对象发生改变时,对象123都要及时收到通知,图形上做出相应的改变
Observer1,Observer2,Observer3
Subject(主题)有更改,应该及时通知相应的观察者,去处理相应的事件
#include
#include
#include
using namespace std;
//观察者抽象类
class Observer
{
public:
//处理消息的接口
virtual void handle(int msgid) = 0;
};
//第1个观察者实例
class Observer1 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 1:
cout << "Observer1 recv msg1!" << endl;
break;
default:
cout << "Observer1 recv unknown msg!" << endl;
break;
}
}
};
//第2个观察者实例
class Observer2 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 2:
cout << "Observer2 recv msg2!" << endl;
break;
default:
cout << "Observer2 recv unknown msg!" << endl;
break;
}
}
};
//第3个观察者实例
class Observer3 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 3:
cout << "Observer3 recv msg3!" << endl;
break;
default:
cout << "Observer3 recv unknown msg!" << endl;
break;
}
}
};
//主题类
class Subject
{
public:
//往容器中注册/添加观察者
void addObserver(Observer* obser, int msgid)
{
_subMap[msgid].push_back(obser); //往msgid对应的观察者链表中插入obser,这句等价于下面注释中的
/*auto it = _subMap.find(msgid);
if (it != _subMap.end())
{
it->second.push_back(obser);
}
else
{
list lis;
lis.push_back(obser);
_subMap.insert({ msgid, lis });
}*/
}
//通知观察者
void dispatch(int msgid)
{
auto it = _subMap.find(msgid);
if (it != _subMap.end())
{
for (Observer* pObser : it->second) //遍历list
{
pObser->handle(msgid);
}
}
else
{
cout << "没有观察者对该消息感兴趣" << endl;
}
}
private:
unordered_map<int, list<Observer*>> _subMap;//msgid - 对该msgid感兴趣的观察者们
};
int main()
{
Subject subject;
Observer *p1 = new Observer1();
Observer *p2 = new Observer2();
Observer *p3 = new Observer3();
subject.addObserver(p1, 1);
subject.addObserver(p2, 2);
subject.addObserver(p3, 3);
int msgid = 0;
while (1)
{
cout << "消息id:" ;
cin >> msgid;
if (msgid == -1)
break;
subject.dispatch(msgid);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)