文章目录
0. 引言
本文简单实现类似 CyberRT 的 DataVisitor
和 DataDispatcher
,使得数据能够被分发给多个订阅者(访客)。
1. 定义 DataVisitor 接口
DataVisitor
是一个接口(抽象基类),定义了所有具体访客需要实现的 Visit
方法。这个方法将用于处理分发的数据。
// DataVisitor.h
#ifndef DATA_VISITOR_H
#define DATA_VISITOR_H
#include <memory>
// 定义一个通用的数据类型,您可以根据需求进行扩展
struct Data {
int id;
std::string content;
};
class DataVisitor {
public:
virtual ~DataVisitor() = default;
// 处理数据的方法
virtual void Visit(const std::shared_ptr<Data>& data) = 0;
};
#endif // DATA_VISITOR_H
2. 实现 DataDispatcher
DataDispatcher
负责管理多个 DataVisitor
,并在有新数据时将其分发给所有注册的访客。
// DataDispatcher.h
#ifndef DATA_DISPATCHER_H
#define DATA_DISPATCHER_H
#include "DataVisitor.h"
#include <vector>
#include <memory>
#include <mutex>
class DataDispatcher {
public:
// 添加一个访客
void AddVisitor(const std::shared_ptr<DataVisitor>& visitor) {
std::lock_guard<std::mutex> lock(mutex_);
visitors_.emplace_back(visitor);
}
// 移除一个访客
void RemoveVisitor(const std::shared_ptr<DataVisitor>& visitor) {
std::lock_guard<std::mutex> lock(mutex_);
visitors_.erase(
std::remove(visitors_.begin(), visitors_.end(), visitor),
visitors_.end()
);
}
// 分发数据给所有访客
void Dispatch(const std::shared_ptr<Data>& data) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto& visitor : visitors_) {
if (visitor) {
visitor->Visit(data);
}
}
}
private:
std::vector<std::shared_ptr<DataVisitor>> visitors_;
std::mutex mutex_; // 保护 visitors_ 的线程安全
};
#endif // DATA_DISPATCHER_H
3. 创建具体的 DataVisitor
实现具体的 DataVisitor
,例如 LoggingVisitor
,用于记录接收到的数据。
// LoggingVisitor.h
#ifndef LOGGING_VISITOR_H
#define LOGGING_VISITOR_H
#include "DataVisitor.h"
#include <iostream>
class LoggingVisitor : public DataVisitor {
public:
void Visit(const std::shared_ptr<Data>& data) override {
std::cout << "LoggingVisitor received data: ID="
<< data->id << ", Content=\""
<< data->content << "\"" << std::endl;
}
};
#endif // LOGGING_VISITOR_H
另一个示例,ProcessingVisitor
,用于处理数据。
// ProcessingVisitor.h
#ifndef PROCESSING_VISITOR_H
#define PROCESSING_VISITOR_H
#include "DataVisitor.h"
class ProcessingVisitor : public DataVisitor {
public:
void Visit(const std::shared_ptr<Data>& data) override {
// 简单示例:打印数据长度
std::cout << "ProcessingVisitor processed data ID="
<< data->id << ", Length="
<< data->content.length() << std::endl;
}
};
#endif // PROCESSING_VISITOR_H
4. 类关系图
这个类关系图展示了 DataDispatcher
和 DataVisitor
之间的继承与关联关系,以及具体的访客类。
5. 测试示例
// main.cpp
#include "DataDispatcher.h"
#include "LoggingVisitor.h"
#include "ProcessingVisitor.h"
#include <memory>
int main() {
// 创建 DataDispatcher
DataDispatcher dispatcher;
// 创建并注册访客
auto logger = std::make_shared<LoggingVisitor>();
auto processor = std::make_shared<ProcessingVisitor>();
dispatcher.AddVisitor(logger);
dispatcher.AddVisitor(processor);
// 创建一些数据并分发
auto data1 = std::make_shared<Data>();
data1->id = 1;
data1->content = "Hello, CyberRT!";
dispatcher.Dispatch(data1);
// 移除一个访客
dispatcher.RemoveVisitor(logger);
// 分发另一个数据
auto data2 = std::make_shared<Data>();
data2->id = 2;
data2->content = "Another data packet.";
dispatcher.Dispatch(data2);
return 0;
}
6. 编译和运行
确保所有头文件和源文件位于正确的位置,并使用以下命令进行编译(假设所有文件在同一目录下):
g++ -std=c++14 main.cpp -o dispatcher
运行程序后,您将看到类似如下的输出:
LoggingVisitor received data: ID=1, Content="Hello, CyberRT!"
ProcessingVisitor processed data ID=1, Length=14
ProcessingVisitor processed data ID=2, Length=19
注意,第二次分发时,LoggingVisitor
已被移除,因此只 ProcessingVisitor
会处理 data2
。