设计模式——观察者(监听者,订阅)模式||线程安全||c++详解
1.什么是观察者模式
观察者模式常用于解耦事件的观察和最终的处理方式。它是一种对象行为模式,如果对象间存在着一种一对多的依赖关系,当一个对象发生改变的时候,其他依赖此对象的对象都要做出相应的改变。
举个例子:大家现在对公众号都不陌生,也经常会关注公众号。那么我们关注公众号的这种模式其实就是一种观察模式,当我们关注的公众号有新内容发布的时候,就会推送给我们这些关注了此公众号的人,那么那么没有关注此公众号的人就不会收到此公众号发布的内容。那么此时的公众号就相当于一个观察者,我们就相当于聆听者。观察者发现有内容推送,就推送给已经关注了它的人,我们呢收到内容,进行阅读(行为改变)。
模式UML图:
如上介绍的例子,订阅公众号的人就相当于Listen,公众号就相当于Observer.
还有一个就是我们现在高等院校选课的一个情景,每个学生都相当于一个聆听者,教务处的系统呢就相当于一个观察者,我们在教务系统选完课以后,就等待教务处通知我们进行上课,每个人都会收到自己所选课程的上课时间表,当教务处发出要上什么课的通知的时候,会将上课时间发送给那些选了这门课程的同学,同学们收到通知去出席课堂。
我们已选课的模式为例实现观察者模式。
2.观察者模式
# include<iostream>
using namespace std;
# include<unordered_map>
//学生基类
class Student
{
public:Student(string name):_name(name) {}//学生上课事件virtual void AttendClass(int classId) = 0;
protected:string _name;
};
//两个学生
class Student1 :public Student
{
public:Student1(string name):Student(name){}void AttendClass(int classId){cout << "学生" << _name << "在上课程" << classId << endl;}
};
class Student2 :public Student
{
public:Student2(string name) :Student(name) {}void AttendClass(int classId){cout << "学生" << _name << "在上课程" << classId << endl;}
};
//教务系统
class DeanSys
{
public://学生选课void SelectCourse(Student* stu, int classId){//判断当前课程是第一次被人选还是已经有人选过了unordered_map<int, list<Student*>>::iterator it = _course.find(classId);if (it == _course.end()){_course[classId].push_back(stu);}else{it->second.push_back(stu);}}//通知学生上课void NoticeStudent(int classId){unordered_map<int, list<Student*>>::iterator it = _course.find(classId);if (it != _course.end()){for (Student* stu : it->second){stu->AttendClass(classId);}}}private://记录学生和课程信息unordered_map<int, list<Student*>> _course;};
int main()
{//实例两个学生Student* stu1 = new Student1("张三");Student* stu2 = new Student2("李四");//教务系统DeanSys dean;//张三选了课程1,2,3dean.SelectCourse(stu1, 1);dean.SelectCourse(stu1, 2);dean.SelectCourse(stu1, 3);//李四选了课程2,3dean.SelectCourse(stu2, 2);dean.SelectCourse(stu2, 3);//教务处发通知让学生上课int classId;while (1){cout << "请输入课程ID:>>";cin >> classId;if (classId <= 0)break;dean.NoticeStudent(classId);}delete stu1;delete stu2;
}
程序运行结果:
3.线程安全的观察者模式
上述代码中,教务处(观察者)通知学生(聆听者)上课的方法下所示:
//通知学生上课void NoticeStudent(int classId){unordered_map<int, list<Student*>>::iterator it = _course.find(classId);if (it != _course.end()){for (Student* stu : it->second){stu->AttendClass(classId);}}}
那么在多线程种调用stu->AttendClass(classId)的时候,观察者没有办法知道聆听者对象是否还存在。这时,如果聆听者对象已经不存在,那么这句代码就会产生错误。这就是多线程下共享对象的安全问题。
我们知道C++11提供了的强弱智能指针能很好的解决这一个问题,关于智能指针的介绍参考我的另一篇文章:
https://blog.csdn.net/qq_42214953/article/details/88936479
接下来就用C++智能指针来实现线程安全的观察者模式:
# include<iostream>
using namespace std;
# include<unordered_map>
class Student
{
public:Student(string name):_name(name) {}//学生上课事件virtual void AttendClass(int classId) = 0;
protected:string _name;
};
class Student1 :public Student
{
public:Student1(string name):Student(name){}void AttendClass(int classId){cout << "学生" << _name << "在上课程" << classId << endl;}
};
class Student2 :public Student
{
public:Student2(string name) :Student(name) {}void AttendClass(int classId){cout << "学生" << _name << "在上课程" << classId << endl;}
};//教务系统
class DeanSys
{
public://学生选课void SelectCourse(weak_ptr<Student> stu, int classId){//判断当前课程是第一次被人选还是已经有人选过了unordered_map<int, list<weak_ptr<Student>>>::iterator it = _course.find(classId);if (it == _course.end()){_course[classId].push_back(stu);}else{it->second.push_back(stu);}}//通知学生上课void NoticeStudent(int classId){unordered_map<int, list<weak_ptr<Student>>>::iterator it = _course.find(classId);if (it != _course.end()){for (list<weak_ptr<Student>>::iterator stu = it->second.begin(); stu != it->second.end(); ++stu){//弱智能指针提升为强智能指针来进行访问操作shared_ptr<Student> p = stu->lock();if (p != nullptr){p->AttendClass(classId);}else{stu = it->second.erase(stu);}}}}private://记录学生和课程信息unordered_map<int, list<weak_ptr<Student>>> _course;};
int main()
{//实例两个学生shared_ptr<Student> stu1( new Student1("张三"));shared_ptr<Student> stu2 ( new Student2("李四"));//教务系统DeanSys dean;//张三选了课程1,2,3dean.SelectCourse(stu1, 1);dean.SelectCourse(stu1, 2);dean.SelectCourse(stu1, 3);//李四选了课程2,3dean.SelectCourse(stu2, 2);dean.SelectCourse(stu2, 3);//教务处发通知让学生上课int classId;while (1){cout << "请输入课程ID:>>";cin >> classId;if (classId <= 0)break;dean.NoticeStudent(classId);}
}
设计模式——观察者(监听者,订阅)模式||线程安全||c++详解相关推荐
- 2.设计模式-观察者模式(发布-订阅模式)
观察者模式(发布-订阅模式)一个简单的使用 简介 例子 被监听者(被观察者) 监听者(观察者) 测试类 简介 观察者模式(有时又被称为模型(Model)-视图(View)模式.源-收听者(Listen ...
- python的编程模式-Python设计模式之状态模式原理与用法详解
本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...
- 设计模式 - 抽象工厂模式(abstract factory pattern) 详解
抽象工厂模式(abstract factory pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/270916 ...
- async spring 默认线程池_Spring boot注解@Async线程池实例详解
这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@A ...
- 线程池源代码详解,参数详解
线程池源代码详解,参数详解 ThreadPoolExecutor 构造函数源代码 public ThreadPoolExecutor(int corePoolSize, int maximumPool ...
- Java线程池ThreadPool详解
Java线程池ThreadPool详解 1. 线程池概述 1.1 线程池简介 1.2 线程池特点 1.3 线程池解决问题 2. 线程池原理分析 2.1 线程池总体设计 2.6 线程池流转状态 2.2 ...
- 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解
前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...
- 怎样进入android模式,安卓手机如何进入Recovery模式的通用方式详解
2014-12-12 15:24:16 安卓手机如何进入Recovery模式的通用方式详解 标签:安卓 Recovery模式 教程 Recovery模式是什么?这里说的Recovery模式主要指的是安 ...
- android doze模式源码分析,Android Doze模式启用和恢复详解
从Android 6.0(API level 23)开始,Android提出了两个延长电池使用时间的省电特性给用户.用户管理可以在没有充电的情况下管理app的行为.当用户一段时间没有使用手机的时候,D ...
最新文章
- 禅道设置bug模板_JPress v3.0 beta.2 发布,修复 bug 和完善产品细节
- or函数python_Python numpy.bitwise_or函数方法的使用
- 由“ASP.NET网站限制访问频率”想到的两点问题(转)
- 【STM32】FreeRTOS创建和删除任务示例(静态方法)(了解)
- python之禅中文原文_Python之禅 - osc_ns45oss7的个人空间 - OSCHINA - 中文开源技术交流社区...
- Solr部分更新MultiValued的Date日期字段时报错及解决方案:Invalid Date String:‘Mon Sep 14 01:48:38 CST 2015‘
- POJ NOI0105-45 金币
- 适用于stuido one的虚拟贝斯手插件:UJAM Virtual Bassist ROYAL for Mac
- CSDN九年的博客时光
- 二次拟合r方_excel曲线拟合中的决定系数R平方是如何求出来的?
- 数字图像处理 冈萨雷斯 中文第三版 习题
- java game nokia 5233 model,诺基亚S60/^3完美运行GBA游戏教程 重回孩提时代
- 搭建 Python 开发环境
- Chrome如何安装第三方扩展插件(crx)
- 小米盒子 改装 无线打印服务器,终于找到了“小米盒子增强版”不定期断网的bug了,2.4G模块bug!...
- 学生评语管理系统软件测试,学生评语管理系统测试版
- 快乐共享(By Robinvane Suen)
- 原来小米手机这么好用,这4大功能,各个都是黑科技,厉害了
- 包裹侠快递查询_全球顶尖技术精英汇聚菜鸟 准备帮助快递攻破体积测量难题...
- MySQL 正负数排序
热门文章
- 小程序weui组件使用
- 夏天吃海鲜的八大禁忌
- 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)
- Proxmox VE7.3+Ceph超融合私有云建设案例(低成本高价值,拿走不谢)
- 好物推荐:2020 年常用软件锦集!帮你解决 90% 的软件问题
- C语言二级必须编译吗,c语言是计算机二级吗
- IDEA导入scala详解
- 理解假设检验: 统计学意义上的显著性水平 (Alpha) 和P值
- MATLAB仪表表盘数字识别
- 知网caj文件转pdf(无需下载任何软件,傻瓜式操作,必看!!!)