使用C++的模板和std::any实现增删改查业务代码复用

概述

本文介绍如何利用C++的模板和std::any类型设计一个通用的对象管理器,以处理不同类型对象的增删改查操作。

实现方法

C++类设计

首先,我们定义一个简单的唯一标识符生成器类 CIdGenerator,使用C++17的随机数生成器来生成唯一的标识符。

// Generate UUID using the <random> library
class CIdGenerator {
 public:
  CIdGenerator() : m_id(generateUUID()) {
  }

  const std::string& to_str() const {
    return m_id;
  }

 private:
  std::string m_id;

  std::string generateUUID() const {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 15);

    std::stringstream ss;
    ss << std::hex;
    for (int i = 0; i < 32; ++i) {
      int random_value = dis(gen);
      char c = (i == 8 || i == 12 || i == 16 || i == 20) ? '-' : '-';
      ss << static_cast<char>(random_value < 10 ? '0' + random_value : 'a' + random_value - 10);
    }
    return ss.str();
  }
};

接下来,我们定义一个通用的对象管理器类 CBaseObjectManager,利用模板技术来处理任意类型对象的增删改查操作。这里使用了std::any作为存储不同类型对象容器的方式,并通过模板函数实现操作。


// Forward declaration for ObjectNotFoundException
class ObjectNotFoundException : public std::runtime_error {
 public:
  explicit ObjectNotFoundException(const std::string& id) : std::runtime_error("Object with ID: " + id + " not found") {
  }
};

// CBaseObjectManager class
class CBaseObjectManager {
 public:
  CBaseObjectManager() = default;
  ~CBaseObjectManager() = default;

  // Get object with the specified ID
  template <typename T>
  T GetObject(const CIdGenerator& id, const std::any& anyVec) {
    try {
      const auto& vec = std::any_cast<const std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        return *it;
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in GetObject");
    }
  }

  // Add object if it doesn't exist, return ID on success
  template <typename T>
  std::string AddObject(const T& src, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&src](const T& t) { return t.GetId() == src.GetId().to_str(); });
      if (it == vec.end()) {
        vec.push_back(src);
        return src.GetId();
      } else {
        throw std::runtime_error("Object with ID: " + src.GetId().to_str() + " already exists");
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in AddObject");
    }
  }

  // Update object with the specified ID
  template <typename T>
  void UpdateObject(const T& src, const CIdGenerator& id, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        *it = src;
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in UpdateObject");
    }
  }

  // Delete object with the specified ID
  template <typename T>
  void DeleteObject(const CIdGenerator& id, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::remove_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        vec.erase(it, vec.end());
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in DeleteObject");
    }
  }
};
性能考虑

在设计和实现上述类时,我们需要特别关注性能优化,尤其是在处理大量数据时的表现。以下是一些性能考虑的实践建议:

  • 避免频繁的动态内存分配和释放: 在使用std::vector时,尽量预先分配适当的容量,以减少动态内存分配和频繁的重新分配。

  • 利用现代C++特性: 使用C++标准库提供的现代化功能,如std::any和智能指针,可以帮助减少内存管理的复杂性和错误。

  • 算法选择和优化: 在使用标准库算法时,选择最适合场景的算法(如使用std::find_if进行查找),并考虑数据结构的特性来优化性能。

示例代码

以下是一个简单的示例,演示了如何使用上述对象管理器类来管理用户对象的增删改查操作。

// Main function example
int main() {
  std::vector<User> users;
  std::any anyVec = std::ref(users);  // Use std::ref to store std::vector<User>

  CBaseObjectManager manager;

  // Example: Add a user
  User newUser("1");
  try {
    std::string id = manager.AddObject(newUser, anyVec);
    std::cout << "Added user with ID: " << id << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  // Example: Update a user
  User updatedUser("1");
  manager.UpdateObject(updatedUser, updatedUser.GetId(), anyVec);
  std::cout << "Updated user with ID: " << updatedUser.GetId() << std::endl;

  // Example: Delete a user
  try {
    manager.DeleteObject<User>(updatedUser.GetId(), anyVec);
    std::cout << "Deleted user with ID: " << updatedUser.GetId() << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  // Example: Query a user
  try {
    User foundUser = manager.GetObject<User>(updatedUser.GetId(), anyVec);
    std::cout << "Found user with ID: " << foundUser.GetId() << std::endl;
  } catch (const ObjectNotFoundException& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  return 0;
}

结论

通过本文的实现和示例,我们展示了如何使用C++的模板和std::any实现通用的增删改查业务逻辑。在设计时,我们特别关注了代码性能的优化,确保在处理大量数据时仍能保持高效。开发团队可以根据具体项目需求和性能要求,进一步调整和优化上述实现,以实现更好的软件质量和用户体验。

参考

  • C++17标准文档
  • cppreference.com,C++参考文档

完整代码

#include <algorithm>
#include <any>
#include <iomanip>
#include <iostream>
#include <random>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

// Generate UUID using the <random> library
class CIdGenerator {
 public:
  CIdGenerator() : m_id(generateUUID()) {
  }

  const std::string& to_str() const {
    return m_id;
  }

 private:
  std::string m_id;

  std::string generateUUID() const {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 15);

    std::stringstream ss;
    ss << std::hex;
    for (int i = 0; i < 32; ++i) {
      int random_value = dis(gen);
      char c = (i == 8 || i == 12 || i == 16 || i == 20) ? '-' : '-';
      ss << static_cast<char>(random_value < 10 ? '0' + random_value : 'a' + random_value - 10);
    }
    return ss.str();
  }
};

// Forward declaration for ObjectNotFoundException
class ObjectNotFoundException : public std::runtime_error {
 public:
  explicit ObjectNotFoundException(const std::string& id) : std::runtime_error("Object with ID: " + id + " not found") {
  }
};

// CBaseObjectManager class
class CBaseObjectManager {
 public:
  CBaseObjectManager() = default;
  ~CBaseObjectManager() = default;

  // Get object with the specified ID
  template <typename T>
  T GetObject(const CIdGenerator& id, const std::any& anyVec) {
    try {
      const auto& vec = std::any_cast<const std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        return *it;
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in GetObject");
    }
  }

  // Add object if it doesn't exist, return ID on success
  template <typename T>
  std::string AddObject(const T& src, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&src](const T& t) { return t.GetId() == src.GetId().to_str(); });
      if (it == vec.end()) {
        vec.push_back(src);
        return src.GetId();
      } else {
        throw std::runtime_error("Object with ID: " + src.GetId().to_str() + " already exists");
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in AddObject");
    }
  }

  // Update object with the specified ID
  template <typename T>
  void UpdateObject(const T& src, const CIdGenerator& id, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::find_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        *it = src;
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in UpdateObject");
    }
  }

  // Delete object with the specified ID
  template <typename T>
  void DeleteObject(const CIdGenerator& id, std::any& anyVec) {
    try {
      auto& vec = std::any_cast<std::vector<T>&>(anyVec);
      auto it = std::remove_if(vec.begin(), vec.end(), [&id](const T& t) { return t.GetId() == id.to_str(); });
      if (it != vec.end()) {
        vec.erase(it, vec.end());
      } else {
        throw ObjectNotFoundException(id.to_str());
      }
    } catch (const std::bad_any_cast&) {
      throw std::runtime_error("Invalid cast: expected std::vector<T> in DeleteObject");
    }
  }
};

// User class
class User {
 public:
  User() : m_id("") {
  }
  explicit User(const std::string& id) : m_id(id) {
  }

  const std::string& GetId() const {
    return m_id;
  }

 private:
  std::string m_id;
};

// Main function example
int main() {
  std::vector<User> users;
  std::any anyVec = std::ref(users);  // Use std::ref to store std::vector<User>

  CBaseObjectManager manager;

  // Example: Add a user
  User newUser("1");
  try {
    std::string id = manager.AddObject(newUser, anyVec);
    std::cout << "Added user with ID: " << id << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  // Example: Update a user
  User updatedUser("1");
  manager.UpdateObject(updatedUser, updatedUser.GetId(), anyVec);
  std::cout << "Updated user with ID: " << updatedUser.GetId() << std::endl;

  // Example: Delete a user
  try {
    manager.DeleteObject<User>(updatedUser.GetId(), anyVec);
    std::cout << "Deleted user with ID: " << updatedUser.GetId() << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  // Example: Query a user
  try {
    User foundUser = manager.GetObject<User>(updatedUser.GetId(), anyVec);
    std::cout << "Found user with ID: " << foundUser.GetId() << std::endl;
  } catch (const ObjectNotFoundException& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  } catch (const std::runtime_error& e) {
    std::cerr << "Error: " << e.what() << std::endl;
  }

  return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘色的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值