C++11通用观察者模式

C++11通用观察者模式

观察者模式是用来解决观察者和被观察者紧耦合的问题,我们需要实现一个观察者管理类,来避免耦合。但同时引入了新问题。管理类在注册以及移除观察者时,在多线程下是不安全的,所以我们需要用mutex来保证管理类是线程安全的。

另外观察者管理类只负责广播注册过的观察者,它不对观察者的生命周期负责,如果观察者已经被销毁,管理类还继续调用该观察者的接口,core dump就是迟早的事情。我们可以用weak_ptr来探测观察者的生命周期,如果观察者存在那么weak_ptr就会提升为shared_ptr,在保证调用安全的同时也不会引起内存泄露,如果直接用shared_ptr来保存观察者的话,那观察者的生命周期会被延长至管理内销毁为止,这也算一种内存泄露。

再者,我们要想实现一个通用的观察者模式,抽象观察者类的Update接口必须支持可变参,但问题是变长模板不能用在虚函数上面,这是因为虚函数的调用是基于运行时多态的机制,而模板实例化是在编译期执行的,如果在编译期不能决定调用哪个函数,又怎么能去根据模板参数实例化出不同的函数。但是我们可以用std::vector<std::any>来模拟变长参数,观察者和被观察者约定一种传参方式,然后观察者根据这种约定来取出参数。而观察者抽象类以及管理类不需要做任何变动。

实现

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
132
133
134
135
136
137
138
139
140
141
142
143
#include <iostream>
#include <list>
#include <memory>
#include <mutex>
#include <vector>
#include <any>
//观察者抽象类
class ManageObserver;
class IObserver {
public:
virtual ~IObserver() = default;
virtual void Update(std::vector<std::any>) = 0;

};
//观察者管理类
class ManageObserver {
public:
ManageObserver() = default;
virtual ~ManageObserver() = default;
ManageObserver(const ManageObserver&) = delete;
ManageObserver(ManageObserver&&) = delete;
ManageObserver& operator=(const ManageObserver&) = delete;
ManageObserver& operator=(ManageObserver&&) = delete;
//注册观察者
void RegisterObserver(std::weak_ptr<IObserver>&& observer) {
std::lock_guard<std::mutex> lock(m_mutex);
m_observers.push_back(std::move(observer));
}
//移除观察者
void RemoveObserver(const std::weak_ptr<IObserver>& observer) {
std::lock_guard<std::mutex> lock(m_mutex);
//无法直接从list中remove
m_observers.remove_if([&](const std::weak_ptr<IObserver>& w) {
bool ret = true;
if (!w.expired()) {
ret = w.lock() == observer.lock();
}
return ret;
});
}
//通知所有观察者
template<typename... Args>
void NotifyObservers(Args&&... args) {
std::lock_guard<std::mutex> lock(m_mutex);
auto iter = m_observers.begin();
while (iter != m_observers.end()) {
//尝试提升这一步是线程安全的
std::shared_ptr<IObserver> obj(iter->lock());
if (obj) {
//提升成功,现在引用计数值至少为2
obj->Update((args)...);
++iter;
}
else {
//观察者已经不存在,移除掉它
iter = m_observers.erase(iter);
}
}
}
private:
std::list<std::weak_ptr<IObserver>> m_observers;
std::mutex m_mutex;
};

//被观察者的实现
class Worker {
public:
Worker(int a = 1,int b = 1):m_a(a),m_b(b) {}
~Worker() = default;
//拷贝构造 赋值构造 移动构造 移动赋值构造 ...

void Register(std::weak_ptr<IObserver> observer) {
mo.RegisterObserver(std::move(observer));
}

void Remove(std::weak_ptr<IObserver> observer) {
mo.RemoveObserver(observer);
}

void multiply() {
int result = m_a * m_b;
std::vector<std::any> args{ result,m_a,m_b};
mo.NotifyObservers(args);
}
private:
int m_a;
int m_b;
ManageObserver mo;
};

//具体的观察者类
class ConcreteObserver : public IObserver {
public:
ConcreteObserver(int id) :m_id(id), result(0) {}
virtual ~ConcreteObserver() = default;
//拷贝构造 赋值构造 移动构造 移动赋值构造 ...

void Update(std::vector<std::any> args){
//和被观察者约定一种传参方式。
result = getArg<int>(0, args);
int a = getArg<int>(1, args);
int b = getArg<int>(2, args);
std::cout<<" Awake : " << a << " * " << b << " = " << result <<" id: "<< m_id << std::endl;
}
private:
template<typename T>
T getArg(int index, std::vector<std::any>& args) {
T ret;
try {
ret = std::any_cast<T>(args[index]);
}
catch (...) {
std::cout << "Err type or index!" << std::endl;
}
return ret;
}
private:
int m_id;
int result;
};

int main()
{
Worker w(3, 5);

std::shared_ptr<ConcreteObserver> pObserver1 = std::make_shared<ConcreteObserver>(1);
std::shared_ptr<ConcreteObserver> pObserver2 = std::make_shared<ConcreteObserver>(2);
{
std::shared_ptr<ConcreteObserver>pObserver3 = std::make_shared<ConcreteObserver>(3);
std::shared_ptr<ConcreteObserver>pObserver4 = std::make_shared<ConcreteObserver>(4);
w.Register(pObserver1);
w.Register(pObserver2);
w.Register(pObserver3);
w.Register(pObserver4);
}
w.multiply();
std::cout << "\n";
w.Remove(pObserver1);
w.Remove(pObserver2);
w.multiply();

return 0;
}


C++11通用观察者模式
https://howl144.github.io/2022/03/23/00010. C++11通用观察者模式/
Author
Deng Ye
Posted on
March 23, 2022
Licensed under