IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】单例模式和观察者模式 -> 正文阅读

[C++知识库]【C++】单例模式和观察者模式

单例模式(创建型)

创建型模式:提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 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 <iostream>
#include <unordered_map>
#include <list>
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<Observer*> 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);
	}
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:22:53  更:2022-04-18 17:23:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:08:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码