设计模式笔记:观察者模式

观察者模式:当一个对象的状态发生改变时,通知订阅者事件发生。

订阅者实现OnEventReceive接收发布者发布的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <map>
#include <list>
#include <memory>
#include <mutex>
#include <iostream>

struct PublicInfo {
std::string eventName;
std::string data;
int code = -1;
};

class Subscribe {
public:
Subscribe(std::string eventName) : eventName_(eventName) {}
virtual void OnEventReceive(const PublicInfo& publicInfo) = 0;
std::string GetEventName();

private:
std::string eventName_;
};

std::string Subscribe::GetEventName()
{
return eventName_;
}

class SubscriberA : public Subscribe {
public:
SubscriberA(std::string eventName) : Subscribe(eventName) {};
void OnEventReceive(const PublicInfo& publicInfo) override;
};

void SubscriberA::OnEventReceive(const PublicInfo& publicInfo)
{
std::cout << "SubscriberA receive event: " << publicInfo.eventName << " data: " << publicInfo.data << " code: " << publicInfo.code << std::endl;
}

class SubscriberB : public Subscribe {
public:
SubscriberB(std::string eventName) : Subscribe(eventName) {};
void OnEventReceive(const PublicInfo& publicInfo) override;
};

void SubscriberB::OnEventReceive(const PublicInfo& publicInfo)
{
std::cout << "SubscriberB receive event: " << publicInfo.eventName << " data: " << publicInfo.data << " code: " << publicInfo.code << std::endl;
}

class EventManager {
public:
static EventManager* GetInstance();
void AddSubscriber(std::weak_ptr<Subscribe> subscribe);
void Notify(PublicInfo& publicInfo);

private:
EventManager() = default;
static EventManager* eventManagerPtr_;
static std::mutex instanceMtx_;
std::map<std::string, std::list<std::weak_ptr<Subscribe>>> subscribers_;
};

EventManager* EventManager::eventManagerPtr_ = nullptr;
std::mutex EventManager::instanceMtx_;

EventManager* EventManager::GetInstance()
{
if (eventManagerPtr_ == nullptr) {
std::lock_guard<std::mutex> lock(instanceMtx_);
if (eventManagerPtr_ == nullptr) {
eventManagerPtr_ = new EventManager();
}
}
return eventManagerPtr_;
}

void EventManager::AddSubscriber(std::weak_ptr<Subscribe> subscribe)
{
std::shared_ptr<Subscribe> subPtr = subscribe.lock();
if (subPtr == nullptr || subPtr->GetEventName().empty()) {
return;
}

auto it = subscribers_.find(subPtr->GetEventName());
if (it != subscribers_.end()) {
it->second.push_back(subscribe);
} else {
std::list<std::weak_ptr<Subscribe>> subscribeList;
subscribeList.push_back(subscribe);
subscribers_.emplace(std::pair<std::string, std::list<std::weak_ptr<Subscribe>>>(subPtr->GetEventName(), subscribeList));
}
}

void EventManager::Notify(PublicInfo& publicInfo)
{
auto it = subscribers_.find(publicInfo.eventName);
if (it != subscribers_.end()) {
for(auto item : it->second) {
std::shared_ptr<Subscribe> subPtr = item.lock();
if (subPtr == nullptr) {
continue;
} else {
subPtr->OnEventReceive(publicInfo);
}
}
}
}

int main()
{
const std::string eventName1 = "eventName1";
const std::string eventName2 = "eventName2";
std::shared_ptr<Subscribe> subA = std::make_shared<SubscriberA>(eventName1);
std::shared_ptr<Subscribe> subB = std::make_shared<SubscriberB>(eventName2);
auto eventManager = EventManager::GetInstance();
eventManager->AddSubscriber(subA);
eventManager->AddSubscriber(subB);

auto eventMgr = EventManager::GetInstance();
PublicInfo publicInfo;
publicInfo.eventName = "eventName1";
publicInfo.code = 0;
publicInfo.data = "data1";
eventMgr->Notify(publicInfo);

PublicInfo publicInfo2;
publicInfo2.eventName = "eventName2";
publicInfo2.code = 1;
publicInfo2.data = "data2";
eventMgr->Notify(publicInfo2);
}

执行结果:

1
2
3
4
ubuntu@ubuntu-ThinkCentre-M800t-1N000:~$ g++ subscribe.cpp
ubuntu@ubuntu-ThinkCentre-M800t-1N000:~$ ./a.out
SubscriberA receive event: eventName1 data: data1 code: 0
SubscriberB receive event: eventName2 data: data2 code: 1