“元信息驱动”逻辑处理所有类型

一、元信息驱动

有多个不同的结构体(如UserProductOrder),需要将它们序列化为键值对字符串。如果每个结构体都写一套序列化逻辑,会产生大量重复代码。通过“元信息驱动”可以用一套通用逻辑处理所有类型。

优化前:重复代码泛滥
#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动态访问
手动调用每个序列化函数循环遍历元信息列表批量处理
新增类型需写新函数(重复劳动)新增类型只需添加元信息(零重复)
技术本质

这种模式的核心是**“用数据描述结构,用通用逻辑处理数据”**:

  1. 元信息(Meta):用结构体/容器存储“类型名称、成员名称、成员指针”等描述性数据,替代硬编码的类型判断。
  2. 通用逻辑:通过模板+成员指针,编写一套与具体类型无关的处理函数(如serialize或你代码中的processType)。
  3. 循环驱动:将所有类型的元信息放入容器,通过循环自动处理所有类型,彻底消除重复代码。

二、针对不同类型添加独立处理逻辑

**元信息中添加“类型专属处理函数”**来实现对不同类型数据的差异化处理,保留“元信息+循环”的通用框架,为每种类型提供灵活的差异化处理,解决“同一流程、不同处理”的需求。

#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;
}
优化说明
  1. 专属处理函数的绑定
    TypeMeta 中新增 processor 成员(类型为 std::function<void(T*, int&)>),用于存储每种类型的处理逻辑。可以绑定:
    • 独立函数(如 processForce);
    • lambda 表达式(如 processViResult 或直接嵌入元信息中);
    • 类成员函数(需用 std::bind 适配)。
  2. 处理逻辑的执行时机
    在通用流程 processType 中,获取数据(getHwData)后立即调用 meta.processor(data, err),确保每种类型的数据都能被专属逻辑处理。
  3. 灵活性与扩展性
    • 新增类型时,只需在元信息中添加对应的处理函数,无需修改通用框架;
    • 处理逻辑的修改仅影响对应类型,不影响其他类型和核心流程;
    • 支持通过 err 错误码在处理函数中做异常分支判断。
  4. 类型安全
    处理函数的参数类型严格绑定到 T*(如 ResStateViForce*),编译期即可检查类型是否匹配,避免指针错误。
输出
获取ResStateViForce数据...
处理Force数据:执行电压校准逻辑
-------------------------
获取ResStateViRelay数据...
处理Relay数据:执行开关状态检查
-------------------------
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值