基本概念
首先定义如下的概念:
- 接收元件:
Receiver<Y,Ym>
- 发送元件:
Sender<Ym>
- 接收者:拥有至少一个接受元(公开成员)的类
- 发送者:拥有至少一个发送元件(公开成员)的类
- 中转者:既是发送者也是接收者的类
其中:Ym是信息类型, Y是接收者类型,接收元件和发送元件必须使用同样的信息类型Ym, 才能建立联系进行信息传递。
信息会从建立连接的发送元件传递到接收元件,发送元件和接收元件之间可以是一对多或多对多地建议联系。
具体说明
元件之间的连接
发送元件和接收元件之间的连接是双向且对等的(与QT的信号和槽函数机制不同),
它们都可以与对方绑定与解绑(一对多,多对多)
1 2 3 4 5 6 7
| sender.bind(receiver); sender.unbind(receiver); sender.unbind_all();
receiver.bind(sender); receiver.unbind(sender); receiver.unbind_all();
|
在发送元件内部会维持一个与自己连接的接收元件记录列表, 可以查询自己的状态
1 2
| sender.num() sender.is_bind(receiver)
|
对接收元件也是一样的
1 2 3
| receiver.num() receiver.is_bind(sender) receiver.is_init()
|
发送者的发送行为
- 创建信息
message
- 在自己的方法内部主动调用发送元件的
sender.exec(message)方法,将消息发送出去
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class TestSender { std::string m_name;
public: MSender<int> int_sender_kernel;
explicit TestSender(const std::string &name): m_name(name) { int_sender_kernel.name(nullptr); }
void emit(int m) { int_sender_kernel.exec(m); } };
|
接收者的接收行为
接收者在构造函数中需要调用init方法初始化接受元,将接收者的指针X和指定的公开方法指针Y传递给它。然后接收元件在收到消息后,就可以正确调用接收者的指定的公开方法,否则无效但不会报错,只是消息丢失了。
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class TestReceiver { std::string m_name;
public: MReceiver<TestReceiver, int> int_receiver_kernel;
explicit TestReceiver(const std::string &name): m_name(name) { int_receiver_kernel.init(this, &TestReceiver::method); }
void method(int m) { std::cout << " " << m_the_name << " receive " << m << " (" << int_receiver_kernel.num() << ")\n"; } };
|
补充说明
为了让消息传递过程可视化,支持给发送元件和接收元件指定名称,
1 2
| sender.name(name_str) receiver.name(name_str)
|
如果设置了, 则在传递消息时会首先把名称字符串传递给std::cout,可以传入一个nullptr用来移除名称字符串。
不要使用detail_开头的接口, 这是不合适的操作, 但又不方便设置私有权限,可能导致指针和析构的错误。
源码
实现代码如下
signal.hpp1 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
| #pragma once
#include <iostream> #include <list>
namespace m_signal {
template <typename Ym> class MReceiverBase;
template <typename Ym> class MSenderBase { public: virtual ~MSenderBase() = default;
virtual void exec(Ym message) const = 0;
virtual bool detail_sender_append(MReceiverBase<Ym> *receiver) = 0; virtual bool detail_sender_remove(MReceiverBase<Ym> *receiver) = 0; };
template <typename Ym> class MReceiverBase { public: virtual ~MReceiverBase() = default;
virtual void exec(Ym message) const = 0;
virtual bool detail_receiver_append(MSenderBase<Ym> *) = 0; virtual bool detail_receiver_remove(MSenderBase<Ym> *) = 0; };
}
template <typename Ym> class MSender;
template <typename Y, typename Ym> class MReceiver final : public m_signal::MReceiverBase<Ym> { private: Y *m_the_receiver = nullptr; void (Y::*m_the_func)(Ym) = nullptr;
std::list<m_signal::MSenderBase<Ym> *> m_the_senders;
const char *m_the_name = nullptr;
public: MReceiver() = default;
MReceiver(const MReceiver &) = delete; MReceiver &operator=(const MReceiver &) = delete;
MReceiver(Y *receiver, void (Y::*func)(Ym)) : m_the_receiver(receiver), m_the_func(func) {}
void init(Y *receiver, void (Y::*func)(Ym)) { m_the_receiver = receiver; m_the_func = func; }
void name(const char *name_str) { m_the_name = name_str; }
void exec(Ym message) const { if (m_the_name != nullptr) std::cout << m_the_name;
if (m_the_receiver && m_the_func) { (m_the_receiver->*m_the_func)(message); } }
void detail_receiver_unbind_all() { auto it = m_the_senders.begin(); while (it != m_the_senders.end()) { (*it)->detail_sender_remove(this); it = m_the_senders.erase(it); } }
~MReceiver() { detail_receiver_unbind_all(); }
bool detail_receiver_append(m_signal::MSenderBase<Ym> *sender) { auto it = m_the_senders.begin(); while (it != m_the_senders.end()) { if (*it == sender) { return false; } ++it; }
m_the_senders.push_back(sender); return true; }
bool detail_receiver_remove(m_signal::MSenderBase<Ym> *sender) { auto it = m_the_senders.begin(); while (it != m_the_senders.end()) { if (*it == sender) { it = m_the_senders.erase(it); return true; } ++it; } return false; }
void detail_receiver_bind(m_signal::MSenderBase<Ym> *sender) { if (detail_receiver_append(sender)) { sender->detail_sender_append(this); } }
void detail_receiver_unbind(m_signal::MSenderBase<Ym> *sender) { if (detail_receiver_remove(sender)) { sender->detail_sender_remove( this); } }
void bind(MSender<Ym> *sender) { detail_receiver_bind(static_cast<m_signal::MSenderBase<Ym> *>(sender)); }
void unbind(MSender<Ym> *sender) { detail_receiver_unbind( static_cast<m_signal::MSenderBase<Ym> *>(sender)); }
void unbind_all() { detail_receiver_unbind_all(); }
bool is_bind(m_signal::MSenderBase<Ym> *sender) const { auto it = m_the_senders.begin(); while (it != m_the_senders.end()) { if (*it == sender) { return true; } ++it; }
return false; }
size_t num() const { return m_the_senders.size(); }
bool is_init() const { return static_cast<bool>(m_the_receiver && m_the_func); } };
template <typename Ym> class MSender final : public m_signal::MSenderBase<Ym> { private: std::list<m_signal::MReceiverBase<Ym> *> m_the_receivers;
const char *m_the_name = nullptr;
public: MSender() = default;
MSender(const MSender &) = delete; MSender &operator=(const MSender &) = delete;
void name(const char *name_str) { m_the_name = name_str; }
void exec(Ym message) const { if (m_the_name != nullptr) std::cout << m_the_name;
auto it = m_the_receivers.begin(); while (it != m_the_receivers.end()) { (*it)->exec(message); ++it; } }
void detail_sender_unbind_all() { auto it = m_the_receivers.begin(); while (it != m_the_receivers.end()) { (*it)->detail_receiver_remove(this); it = m_the_receivers.erase(it); } }
~MSender() { detail_sender_unbind_all(); }
bool detail_sender_append(m_signal::MReceiverBase<Ym> *receiver) { auto it = m_the_receivers.begin(); while (it != m_the_receivers.end()) { if (*it == receiver) { return false; } ++it; }
m_the_receivers.push_back(receiver); return true; }
bool detail_sender_remove(m_signal::MReceiverBase<Ym> *receiver) { auto it = m_the_receivers.begin(); while (it != m_the_receivers.end()) { if (*it == receiver) { it = m_the_receivers.erase(it); return true; } ++it; } return false; }
void detail_sender_bind(m_signal::MReceiverBase<Ym> *receiver) { if (detail_sender_append(receiver)) { receiver->detail_receiver_append( this); } }
void detail_sender_unbind(m_signal::MReceiverBase<Ym> *receiver) { if (detail_sender_remove(receiver)) { receiver->detail_receiver_remove( this); } }
template <typename Y> void bind(MReceiver<Y, Ym> *receiver) { detail_sender_bind( static_cast<m_signal::MReceiverBase<Ym> *>(receiver)); }
template <typename Y> void unbind(MReceiver<Y, Ym> *receiver) { detail_sender_unbind( static_cast<m_signal::MReceiverBase<Ym> *>(receiver)); }
void unbind_all() { detail_sender_unbind_all(); }
bool is_bind(m_signal::MReceiverBase<Ym> *receiver) const { auto it = m_the_receivers.begin(); while (it != m_the_receivers.end()) { if (*it == receiver) { return true; } ++it; }
return false; }
size_t num() const { return m_the_receivers.size(); } };
|
测试代码以及运行结果如下
main.cpp1 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
| #include <string>
#include "signal.hpp"
class TestReceiver { std::string m_the_name;
public: MReceiver<TestReceiver, int> int_receiver_kernel; MSender<int> int_sender_kernel;
explicit TestReceiver(const char *name) { m_the_name = std::string(name); int_receiver_kernel.init(this, &TestReceiver::method); }
void method(int m) { std::cout << " " << m_the_name << " receive " << m << " (" << int_receiver_kernel.num() << ")\n";
if (int_sender_kernel.num() > 0) { emit(m); } }
void emit(int m) { std::cout << m_the_name << " send " << m << ": (" << int_sender_kernel.num() << ")\n";
int_sender_kernel.exec(m); } };
class TestSender { std::string m_the_name;
public: MSender<int> int_sender_kernel;
explicit TestSender(const char *name) { m_the_name = std::string(name); int_sender_kernel.name("TestSender int_sender_kernel\n"); int_sender_kernel.name(nullptr); }
void emit(int m) { std::cout << m_the_name << " send " << m << ": (" << int_sender_kernel.num() << ")\n";
int_sender_kernel.exec(m); } };
int main() { TestSender Ada("Ada");
TestReceiver Mike("Mike"); TestReceiver John("John"); TestReceiver Jack("Jack");
Ada.int_sender_kernel.bind(&Mike.int_receiver_kernel); Ada.int_sender_kernel.bind(&John.int_receiver_kernel);
Ada.emit(1);
Ada.int_sender_kernel.bind(&Jack.int_receiver_kernel); Jack.int_sender_kernel.bind(&John.int_receiver_kernel);
Ada.emit(2);
Ada.int_sender_kernel.unbind( &Jack.int_receiver_kernel);
Ada.emit(3);
John.int_receiver_kernel.unbind_all();
Ada.emit(4);
return 0; }
|