2

在我之前的工作中,大部分程序处理依赖于存储在数据库中的持久数据。

所以DB数据模型主导了运行时程序的数据结构。因此,我们使用主键值作为对其他对象的引用非常方便。

例如 :

1 - 考虑到我们有一家公司通过互联网向客户销售书籍等商品。我们有三个类:Book、Order 和 Customer。

  • Book 类包含有关书籍的不同信息以及唯一标识符,例如 ISBN 号。

  • 客户类包含公司需要知道的所有数据(通常还有更多),以便将书籍运送给他们的客户,例如电子邮件地址。客户对象还有一个唯一的持久 id 来识别它们。

  • 因此 Order 类包含两个关系引用int isbn;(书籍 ID)和 int customer_id;

    在本示例中,订单类方法不需要访问客户数据或书籍数据,因此订单类不需要依赖它们。

2 - 如果我们现在考虑另一个用于编写和发送订单确认电子邮件的类:

class OrderMailer
{
   // Customer index
   std::map<int, Customer *> customers;
...
   // we have a function that send email with low level parameters
   void sendEmail(const std::string& mailAddress, const std::string& body);

   // and we have another method that simply sends the email for a given order
   void sendEmail(const Order& order);
};

sendEmail(const Order& order) 方法需要获取客户的电子邮件地址,因此需要从其标识符中获取对象。

这就是为什么我们有一个地图,然后地址将被这样访问

const std::string& target = customers[order.customer_id]->emailAddress; // not found test omitted for reading.

这就是想法。

问题部分:

我在几年中使用这种引用方式,没有问自己“这真的是个好主意吗”,因为:

  • 对象/记录 ID 是在公司中识别对象的方式

  • 这种无处不在的持久性 ID(代码、日志、与其他 IT 的讨论)

  • 运行时数据结构总是反映 DB 数据模型(它可能不是一个可靠的论点,但在 DB 世界和运行时世界(c++、python、js)之间切换时非常有用)

我不再在这家公司工作,但在处理持久记录时我保持这种编程方式,我不确定我是否做对了。

我们做了什么?

我们使用了一种引用对象的逻辑方式,而不是使用语言提供的方式:指针或 C++ 引用。当我这样说的时候,这听起来真的很糟糕。

从我的角度来看,这是使用这种“方法”的利弊列表:

  • 优点:

    • 如果有底层的关系数据模型,运行时数据结构反映了数据模型,事情就更容易理解了
    • 这避免了类的无用耦合(在示例中,Order 不依赖于 Customer 和 Book 类)
    • 唯一标识符可以是易于阅读的字符串
  • 缺点:

    • 为什么不使用语言的基本特性,即指针和引用来做到这一点?这听起来是一个糟糕的方法。
    • 每次我们想要访问逻辑引用对象的数据时,我们都需要使用字典/索引(映射)

如前所述,我不确定使用逻辑/关系引用是否是一件好事。是否有一些规则可以应用来决定是否使用这种方法?我很乐意听取您对此的意见。

4

1 回答 1

0

好吧,这就是我会做的。因为这是 C++,如果我们使用标准容器。为什么不使用迭代器。我还添加了一些打印代码以便于测试。

如果您想要迭代器稳定性,请将向量更改为列表。为了更好的查找操作,请查看boost::multi_index http://www.boost.org/doc/libs/1_53_0/libs/multi_index/doc/index.htmlboost::multi_index如果迭代器稳定性很重要,也很好用。

boost::serialization如果您想将数据结构写入文件,它可能也很容易使用。

#include <string>
#include <iostream>
#include <vector>

struct Streamable
{
  virtual ~Streamable() = default;
  virtual std::ostream& print(std::ostream& ost) const = 0;
};

std::ostream& operator<<(std::ostream& ost, const Streamable& str)
{
  return str.print(ost);
}

struct Customer : public Streamable
{
  std::string name_m;
  Customer(const std::string& name_):name_m(name_)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    return ost<<name_m;
  }
};

struct CustomerColl : public std::vector<Customer>,
              public Streamable
{
  CustomerColl(std::initializer_list<Customer> customers)
    :std::vector<Customer>(customers)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    ost<<"Customers:"<<std::endl;
    for(const auto& c: *this)
    {
      ost<<c<<std::endl;
    }
    return ost;
  }
};

struct Book : public Streamable
{
  std::string title_m;
  unsigned int isbn_m;

  Book(const std::string& title_, const unsigned int& isbn_)
    :title_m(title_),isbn_m(isbn_)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    return ost<<title_m<<":{"<<isbn_m<<"}";
  }
};

struct BookColl : public std::vector<Book>,
          public Streamable
{
  BookColl(std::initializer_list<Book> books)
    :std::vector<Book>(books)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    ost<<"Books:"<<std::endl;
    for(const auto& b: *this)
    {
      ost<<b<<std::endl;
    }
    return ost;
  }
};

struct Order : public Streamable
{
  BookColl::const_iterator book_m;
  CustomerColl::const_iterator customer_m;

  Order(const BookColl::const_iterator& book_,
    const CustomerColl::const_iterator& customer_)
    :book_m(book_),customer_m(customer_)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    return ost<<"["<<*customer_m<<"->"<<*book_m<<"]";
  }
};

struct OrderColl : public std::vector<Order>,
           public Streamable
{
  OrderColl(std::initializer_list<Order> orders)
    :std::vector<Order>(orders)
  {}
  std::ostream& print(std::ostream& ost) const
  {
    ost<<"Orders:"<<std::endl;
    for(const auto& o: *this)
    {
      ost<<o<<std::endl;
    }
    return ost;
  }
};

int main()
{
  CustomerColl customers{{"Anna"},{"David"},{"Lisa"}};
  BookColl books{{"C++",123},{"Java",234},{"Lisp",345}};

  OrderColl orders{{books.begin(),customers.begin()},{books.begin(),customers.begin()+1},{books.end()-1,customers.begin()+2}};

  std::cout<<customers<<std::endl;
  std::cout<<books<<std::endl;
  std::cout<<orders<<std::endl;

  return 0;
}
于 2013-03-06T11:59:16.267 回答