设计场景:
发布-订阅
对于感兴趣的公众号,客户选择了订阅,当公众号发布新文章(伴随着更新发布状态)时,它会通知已订阅的客户们,客户们自身随发布而更新自身状态;
问题描述:
(1)观察者模式定义:一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题对象自身状态发生变化时,会通知所有观察者对象,是他们能够自动更新自己;
(2)观察者模式很好的体现了开放-封闭原则、依赖倒转原则的思想;解除耦合,让耦合的双方依赖于抽象,而不是依赖于具体;从而使各自的变化不会互相影响;
(3)开放-封闭:对自身扩展开放,对自身修改封闭;
(4)依赖倒转:程序依赖抽象,而不是程序与程序依赖;
(5)使用时机:当一个对象的改变需要同时改变其他对象(不知数量)时;
代码实现:
(1)代码采用观察者模式实现了设计场景中的需求,同时实现过程中尽可能的扣紧观察者模式的定义;
(2)注意:发布与订阅是一对多的关系,这也是在观察者类没有针对抽象主题类编程,而是针对具体主题类编程的原因;若是多对多的关系,可考虑采用针对抽象类编程,可以有效的解除观察者类和主题类之间的耦合;注意当前代码仅仅实现的是降低而不是解除;
#pragma once
#include<vector>
#include<string>
using namespace std;
#include"observe.h"
// 主题类-----抽象类
class Subject
{
public:
// 添加观察者
virtual void attach(Observe* observe) = 0;
// 删除观察者
virtual void detach() = 0; // 简化操作:默认只删除最后一个添加的观察者
// 发布通知
virtual void notify(string content,string flag) = 0;
};
#pragma once
#include"subject.h"
// 具体主题对象-----继承Subject抽象类
class ConcreteSubject : public Subject
{
public:
ConcreteSubject() {
m_state = "未发送";
}
void attach(Observe* observe) override // 针对抽象类编程,降低类之间的耦合
{
m_observes.push_back(observe);
}
void detach() override
{
m_observes.pop_back();
}
void notify(string content,string flag) override
{
for (int i = 0; i < m_observes.size(); i++)
{
m_observes.at(i)->update(content,flag);
}
}
// get
string get_SubjectState() { return m_state; }
// set
void set_SubjectState(string state) { m_state = state; }
private:
vector<Observe*> m_observes; // 观察者集合 (一个主题:多个观察者)
string m_state; // 状态
};
#pragma once
#include<string>
using namespace std;
// 观察者类-----抽象类
class Observe
{
public:
virtual void update(string content,string flag) = 0; // 更新观察者自身
};
#pragma once
#include"observe.h"
#include"concrete_subject.h"
#include<iostream>
// 具体观察者类-----继承Observe抽象类
class ConcreteObserve : public Observe
{
public:
ConcreteObserve(ConcreteSubject* subject,string name) // 这里不用抽象类的原因是 (一对多的关系,若是多对多,可以优化成针对抽象编程)
{
m_subject = subject;
m_name = name;
}
void update(string content,string flag) override
{
if (flag == "已发送")
{
m_state = "已收到";
}
else
{
m_state = "未收到";
}
cout << "观察者:" << m_name << "对于主题:" << content << " 展示的新状态是:" << m_state << endl;
}
private:
string m_name; // 名称
string m_state; // 状态
ConcreteSubject* m_subject; // 订阅的主题
};
#include"concrete_observe.h"
#include"concrete_subject.h"
#include"observe.h"
#include"subject.h"
int main()
{
// 创建具体主题对象
ConcreteSubject* s = new ConcreteSubject();
// 为主题对象添加具体观察者对象 同时将观察者于订阅的主题绑定 (一对多关系)
s->attach(new ConcreteObserve(s, "阿强"));
s->attach(new ConcreteObserve(s, "阿珍"));
// 订阅号主题发布内容,同时将状态置 已发送
s->notify("元宇宙将重塑人类数字地图","已发送");
}
观察者:阿强对于主题:元宇宙将重塑人类数字地图 展示的新状态是:已收到
观察者:阿珍对于主题:元宇宙将重塑人类数字地图 展示的新状态是:已收到