一、元信息驱动
有多个不同的结构体(如User、Product、Order),需要将它们序列化为键值对字符串。如果每个结构体都写一套序列化逻辑,会产生大量重复代码。通过“元信息驱动”可以用一套通用逻辑处理所有类型。
优化前:重复代码泛滥
#include <string>
#include <sstream>
// 定义多个结构体
struct User {
int id;
std::string name;
int age;
};
struct Product {
std::string code;
double price;
int stock;
};
struct Order {
int orderId;
std::string userId;
double total;
};
// 为每个结构体写序列化函数(重复逻辑)
std::string serializeUser(const User& u) {
std::stringstream ss;
ss << "User{id=" << u.id
<< ", name=" << u.name
<< ", age=" << u.age << "}";
return ss.str();
}
std::string serializeProduct(const Product& p) {
std::stringstream ss;
ss << "Product{code=" << p.code
<< ", price=" << p.price
<< ", stock=" << p.stock << "}";
return ss.str();
}
std::string serializeOrder(const Order& o) {
std::stringstream ss;
ss << "Order{orderId=" << o.orderId
<< ", userId=" << o.userId
<< ", total=" << o.total << "}";
return ss.str();
}
// 使用时需要手动调用每个函数
int main() {
User u{1, "Alice", 20};
Product p{"P001", 99.5, 100};
Order o{1001, "U1", 199.0};
std::cout << serializeUser(u) << "\n";
std::cout << serializeProduct(p) << "\n";
std::cout << serializeOrder(o) << "\n";
return 0;
}
优化后:元信息驱动+通用逻辑
#include <string>
#include <sstream>
#include <vector>
#include <functional>
// 结构体定义不变(User、Product、Order同上)
struct User { int id; std::string name; int age; };
struct Product { std::string code; double price; int stock; };
struct Order { int orderId; std::string userId; double total; };
// 1. 定义成员元信息:存储成员名称和访问方法(成员指针)
template <typename StructType, typename MemberType>
struct MemberMeta {
std::string name; // 成员名称(如"id"、"name")
MemberType (StructType::*memberPtr); // 成员指针(如&User::id)
};
// 2. 定义结构体元信息:包含结构体名称和成员列表
template <typename StructType>
struct StructMeta {
std::string structName; // 结构体名称(如"User")
std::vector<auto> members; // 成员元信息列表
};
// 3. 为每个结构体定义元信息(核心:用数据描述结构)
const auto userMeta = StructMeta<User>{
"User",
{
MemberMeta<User, int>{ "id", &User::id },
MemberMeta<User, std::string>{ "name", &User::name },
MemberMeta<User, int>{ "age", &User::age }
}
};
const auto productMeta = StructMeta<Product>{
"Product",
{
MemberMeta<Product, std::string>{ "code", &Product::code },
MemberMeta<Product, double>{ "price", &Product::price },
MemberMeta<Product, int>{ "stock", &Product::stock }
}
};
const auto orderMeta = StructMeta<Order>{
"Order",
{
MemberMeta<Order, int>{ "orderId", &Order::orderId },
MemberMeta<Order, std::string>{ "userId", &Order::userId },
MemberMeta<Order, double>{ "total", &Order::total }
}
};
// 4. 通用序列化函数(一套逻辑处理所有结构体)
template <typename StructType>
std::string serialize(const StructType& obj, const StructMeta<StructType>& meta) {
std::stringstream ss;
ss << meta.structName << "{";
for (size_t i = 0; i < meta.members.size(); ++i) {
const auto& member = meta.members[i];
// 通过成员指针访问对象的成员(核心逻辑)
ss << member.name << "=" << (obj.*(member.memberPtr));
if (i != meta.members.size() - 1) ss << ", ";
}
ss << "}";
return ss.str();
}
// 5. 循环批量处理所有类型
int main() {
// 数据实例
User u{1, "Alice", 20};
Product p{"P001", 99.5, 100};
Order o{1001, "U1", 199.0};
// 元信息列表(所有类型在这里注册)
const std::vector<auto> allMetas = {
std::make_pair(std::ref(u), std::ref(userMeta)),
std::make_pair(std::ref(p), std::ref(productMeta)),
std::make_pair(std::ref(o), std::ref(orderMeta))
};
// 循环序列化所有对象(一行代码处理所有类型)
for (const auto& [obj, meta] : allMetas) {
std::cout << serialize(obj.get(), meta.get()) << "\n";
}
return 0;
}
核心优化思路对比
| 优化前 | 优化后 |
|---|---|
| 每个类型写一套序列化函数 | 一套通用serialize函数处理所有类型 |
硬编码成员访问(如u.id) | 通过成员指针memberPtr动态访问 |
| 手动调用每个序列化函数 | 循环遍历元信息列表批量处理 |
| 新增类型需写新函数(重复劳动) | 新增类型只需添加元信息(零重复) |
技术本质
这种模式的核心是**“用数据描述结构,用通用逻辑处理数据”**:
- 元信息(Meta):用结构体/容器存储“类型名称、成员名称、成员指针”等描述性数据,替代硬编码的类型判断。
- 通用逻辑:通过模板+成员指针,编写一套与具体类型无关的处理函数(如
serialize或你代码中的processType)。 - 循环驱动:将所有类型的元信息放入容器,通过循环自动处理所有类型,彻底消除重复代码。
二、针对不同类型添加独立处理逻辑
**元信息中添加“类型专属处理函数”**来实现对不同类型数据的差异化处理,保留“元信息+循环”的通用框架,为每种类型提供灵活的差异化处理,解决“同一流程、不同处理”的需求。
#include <vector>
#include <functional>
#include <iostream> // 用于示例输出
#define RESULT_NUM 2
struct ReqStateViForce {};
struct ReqStateViRelay {};
struct Response {
union Response {
ResStateViForce force;
ResStateViRelay relay;
} response;
};
#define VI_FORCE_TYPE_QUERY 1
#define VI_RELAY_TYPE_QUERY 2
template <typename T, T (Response::Response::*MemberPtr)>
void getHwData(int& err, T* data, size_t size, uint8_t reqType, uint32_t cardId, uint32_t subId) {
// 模拟获取数据(实际实现不变)
std::cout << "获取" << typeid(T).name() << "数据...\n";
}
// 1. 元信息结构体
template <typename T>
struct TypeMeta {
using Type = T;
T (Response::Response::*memberPtr); // 成员指针
uint8_t reqType; // 请求类型
std::function<size_t()> sizeFunc; // 大小计算函数
// 新增:类型专属处理函数(输入为获取到的数据指针和错误码)
std::function<void(T*, int&)> processor; // 处理逻辑
};
// 2. 为每种类型定义专属处理函数(示例)
void processForce(ResStateViForce* data, int& err) {
if (err == 0) {
std::cout << "处理Force数据:执行电压校准逻辑\n";
// 具体处理:如解析数据、校验、存储等
}
}
void processRelay(ResStateViRelay* data, int& err) {
if (err == 0) {
std::cout << "处理Relay数据:执行开关状态检查\n";
// 具体处理:如状态判断、日志记录等
}
}
// 3. 定义元信息数组:绑定处理函数
const std::vector<auto> typeMetas = {
TypeMeta<ResStateViForce>{
&Response::Response::force,
VI_FORCE_TYPE_QUERY,
[](){ return sizeof(ResStateViForce); },
processForce // 绑定处理函数
},
TypeMeta<ResStateViRelay>{
&Response::Response::relay,
VI_RELAY_TYPE_QUERY,
[](){ return sizeof(ResStateViRelay); },
processRelay // 绑定处理函数, 或直接嵌入lambda
},
};
// 4. 通用处理函数:获取数据后调用专属处理函数
template <typename Meta>
void processType(int& err, uint32_t cardId, uint32_t subId, const Meta& meta) {
using T = typename Meta::Type;
T* data = (T*)new char[meta.sizeFunc()];
// 1. 获取数据
getHwData<T, meta.memberPtr>(err, data, meta.sizeFunc(), meta.reqType, cardId, subId);
// 2. 调用该类型的专属处理函数
if (data != nullptr) {
meta.processor(data, err); // 差异化处理
}
// 3. 释放内存
delete[] (char*)data;
}
// 5. 主逻辑:循环处理所有类型
int main() {
int err = 0;
uint32_t cardId = 0;
uint32_t subId = 0;
for (const auto& meta : typeMetas) {
processType(err, cardId, subId, meta);
std::cout << "-------------------------\n";
}
return 0;
}
优化说明
- 专属处理函数的绑定
在TypeMeta中新增processor成员(类型为std::function<void(T*, int&)>),用于存储每种类型的处理逻辑。可以绑定:- 独立函数(如
processForce); - lambda 表达式(如
processViResult或直接嵌入元信息中); - 类成员函数(需用
std::bind适配)。
- 独立函数(如
- 处理逻辑的执行时机
在通用流程processType中,获取数据(getHwData)后立即调用meta.processor(data, err),确保每种类型的数据都能被专属逻辑处理。 - 灵活性与扩展性
- 新增类型时,只需在元信息中添加对应的处理函数,无需修改通用框架;
- 处理逻辑的修改仅影响对应类型,不影响其他类型和核心流程;
- 支持通过
err错误码在处理函数中做异常分支判断。
- 类型安全
处理函数的参数类型严格绑定到T*(如ResStateViForce*),编译期即可检查类型是否匹配,避免指针错误。
输出
获取ResStateViForce数据...
处理Force数据:执行电压校准逻辑
-------------------------
获取ResStateViRelay数据...
处理Relay数据:执行开关状态检查
-------------------------

被折叠的 条评论
为什么被折叠?



