一、基本概念
基于map的观察者模式:定义对象之间的一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。又称为依赖,发布-订阅。
存在两个部分:
- 观察者:观察事件是否发生,发生通知监听者(具体观察者)。
- 监听者 (具体观察者):处理事件。
如微信的消息提醒,订阅号提醒,就是观察者监听是否有消息到来,发生后,提醒监听者去处理。
【1. 优点:】
- 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息传递机制,并抽象了更新接口,使得可以有各种各样的表示层充当具体观察者角色。
- 观察者模式在观察目标和观察者之间建立了一个抽象的耦合,观察者对象只需维持一个抽象观察者的集合,无需了解其具体观察者。
- 观察者模式支持广播通信,观察目标会像所有已注册的观察者发起通知,降低了一对多系统的设计难度。
- 观察者模式满足开放-封闭原则,增加新的具体观察者无须修改原有的系统代码。
【2. 缺点:】
- 如果一个观察目标对象有很多的直接观察者和间接观察者,那么所有的观察者接收消息会 耗费大量的时间。
- 如果观察者和被观察者之间存在循环依赖,那么观察目标会出发它们之间进行循环调用,可能导致系统崩溃。
【3. 使用场景:】
- 当一个抽象对象有两个方面,其中一方面依赖于另一方面,将这两者封装在独立的对象中,实现独立的改变,进行依赖。
- 当一个对象的的数据变化时需要通知其他对象,不希望这些对象是紧密耦合的,即不知道具体的对象是谁。
- 当一个对象的数据变化时需要通知其他对象,但它并不需要清楚其他对象的具体变化。
二、设计观察者模式
观察者的 设计类图 如下所示:
- Subject:抽象主题,又称为抽象观察者。把所有观察对象(监听者)保存到一个集合中,可以使用容器保存。提供注册,删除,通知三个接口。
- ConcreteSubject:具体主体,又称为观察者,继承抽象主题得到,实现三个接口。
- Obsever:抽象观察对象,又称为监听者。提供了处理事件的接口。
- ConcreteObsever:具体观察对象,又称为监听者,继承Obsever得到,实现处理事件具体功能
在观察者中保存监听者,采用map键值保存<事件,感兴趣的监听者>,是1-多的关系,可以将其转换为<1,一个监听者集合(可以使用vector存储)>,变为了1-1的关系,表示了哪些监听者对事件感兴趣。
三、实例
观察者监听三个监听者,监听者1对事件1,2感兴趣;监听者2对事件2,3感兴趣;监听者3对事件1,3感兴趣。对类之间的设计如下:
观察者类需要提供成员函数:
【1. 注册事件函数:】 将<事件-监听者>进行注册,采用容器vector保存监听者集合。假如现在注册1号事件的监听者,那么有两种情况:1号事件被注册,1号事件未注册;
- 故先在vector集合中查找是否存在1号事件,存在直接将事件插入vector集合即可。
- 不存在,先开辟集合,将事件放入集合,将集合插入map中。
【通知监听者处理事件】
- 先查找是否在map中存在对它感兴趣的事件,存在,提供迭代器遍历监听者集合,调用监听者处理事件函数。
- 不存在,打印错误信息。
提供私有成员变量:map, 将事件-监听者集合放入map中,集合用vector存储,存储监听者抽象类指针,可以用基类指针指向派生类对象,访问任意监听者。
监听者类:提供处理函数即可:对自己感兴趣的事件进行处理,进行一个简单的打印。
那么代码如下:
# include<iostream>
# include<deque>
# include<vector>
# include<list>
# include<algorithm>
# include<iterator>
# include<set>
# include<map>
# include<string>