C++ 类 应该包含协议缓冲区消息还是 constructed/populated 来自协议缓冲区消息
Should C++ classes contain or be constructed/populated from protocol buffer messages
对于 C++ 中的协议缓冲区,我想知道是在我的 class 中包含一个 protobuf 消息更好,还是让它从外部 protobuf 消息构造并填充它更好。
我找不到描述此案例最佳实践的示例。我特别担心两种设计之间的性能差异。
在我的处理中,我会遇到一些情况,我将只从我的消息中读取几个字段,然后将消息路由到另一个进程(可能在将消息发送回之前对消息进行操作),以及其他情况我的对象将有很长的生命周期,并且在再次序列化之前会被多次使用。在第一种情况下,我可能会直接对 protobuf 消息进行操作,甚至不需要我的 class、execpt 来适应现有接口。
这是一个示例消息:
package example;
message Example {
optional string name = 1;
optional uint32 source = 2;
optional uint32 destination = 3;
optional uint32 value_1 = 4;
optional uint32 value_2 = 5;
optional uint32 value_3 = 6;
}
我的 class 可以看到以下设计之一。我知道这些 classes 除了访问数据之外没有做任何其他事情,但这不是我在这个问题上想要关注的。
作文
class Widget
{
public:
Widget() : message_() {}
Widget(const example::Example& other_message)
: message_(other_message) {}
const example::Example& getMessage() const
{ return message_; }
void populateMessage(example::Example& message) const
{ message = message_; }
// Some example inspectors filled out...
std::string getName() const
{ return message_.name(); }
uint32_t getSource() const;
{ return message_.source(); }
uint32_t getDestination() const;
uint32_t getValue1() const;
uint32_t getValue2() const;
uint32_t getValue3() const;
// Some example mutators filled out...
void setName(const std::string& new_name)
{ message_.set_name(new_name); }
void setSource(uint32_t new_source);
{ message_.set_source(new_source); }
void setDestination(uint32_t new_destination);
void setValue1(uint32_t new_value);
void setValue2(uint32_t new_value);
void setValue3(uint32_t new_value);
private:
example::Example message_;
};
标准数据成员
class Widget
{
public:
Widget();
Widget(const example::Example& other_message)
: name_(other_message.name()),
source_(other_message.source()),
destination_(other_message.destination()),
value_1_(other_messsage.value_1()),
value_2_(other_messsage.value_2()),
value_3_(other_messsage.value_3())
{}
example::Example getMessage() const
{
example::Example message;
populateMessage(message);
return message;
}
void populateMessage(example::Example& message) const
{
message.set_name(name_);
message.set_source(source_);
message.set_value_1(value_1_);
message.set_value_2(value_2_);
message.set_value_3(value_3_);
}
// Some example inspectors filled out...
std::string getName() const
{ return name_; }
uint32_t getSource() const;
{ return source_; }
uint32_t getDestination() const;
uint32_t getValue1() const;
uint32_t getValue2() const;
uint32_t getValue3() const;
// Some example mutators filled out...
void setName(const std::string& new_name)
{ name_ = new_name; }
void setSource(uint32_t new_source);
{ source_ = new_source; }
void setDestination(uint32_t new_destination);
void setValue1(uint32_t new_value);
void setValue2(uint32_t new_value);
void setValue3(uint32_t new_value);
private:
std::string name_;
uint32_t source_;
uint32_t destination_;
uint32_t value_1_;
uint32_t value_2_;
uint32_t value_3_;
};
这里没有可识别的"best practice"。我已经看到了很多这两种方式的例子,甚至看到了两种方式都有效的编写程序。有些人对此有很强的看法,但我认为这取决于用例。例如,正如您所说,如果您计划将大部分数据转发到另一台服务器,那么保留 protobuf 对象就很有意义。但其他时候你有更方便的内部表示——例如,在 protobufs 添加对地图的本地支持之前,如果你有一个将地图表示为 key/value 对的重复列表的 protobuf,你可能想要转换它提前 std::map
。
对于 C++ 中的协议缓冲区,我想知道是在我的 class 中包含一个 protobuf 消息更好,还是让它从外部 protobuf 消息构造并填充它更好。
我找不到描述此案例最佳实践的示例。我特别担心两种设计之间的性能差异。
在我的处理中,我会遇到一些情况,我将只从我的消息中读取几个字段,然后将消息路由到另一个进程(可能在将消息发送回之前对消息进行操作),以及其他情况我的对象将有很长的生命周期,并且在再次序列化之前会被多次使用。在第一种情况下,我可能会直接对 protobuf 消息进行操作,甚至不需要我的 class、execpt 来适应现有接口。
这是一个示例消息:
package example;
message Example {
optional string name = 1;
optional uint32 source = 2;
optional uint32 destination = 3;
optional uint32 value_1 = 4;
optional uint32 value_2 = 5;
optional uint32 value_3 = 6;
}
我的 class 可以看到以下设计之一。我知道这些 classes 除了访问数据之外没有做任何其他事情,但这不是我在这个问题上想要关注的。
作文
class Widget
{
public:
Widget() : message_() {}
Widget(const example::Example& other_message)
: message_(other_message) {}
const example::Example& getMessage() const
{ return message_; }
void populateMessage(example::Example& message) const
{ message = message_; }
// Some example inspectors filled out...
std::string getName() const
{ return message_.name(); }
uint32_t getSource() const;
{ return message_.source(); }
uint32_t getDestination() const;
uint32_t getValue1() const;
uint32_t getValue2() const;
uint32_t getValue3() const;
// Some example mutators filled out...
void setName(const std::string& new_name)
{ message_.set_name(new_name); }
void setSource(uint32_t new_source);
{ message_.set_source(new_source); }
void setDestination(uint32_t new_destination);
void setValue1(uint32_t new_value);
void setValue2(uint32_t new_value);
void setValue3(uint32_t new_value);
private:
example::Example message_;
};
标准数据成员
class Widget
{
public:
Widget();
Widget(const example::Example& other_message)
: name_(other_message.name()),
source_(other_message.source()),
destination_(other_message.destination()),
value_1_(other_messsage.value_1()),
value_2_(other_messsage.value_2()),
value_3_(other_messsage.value_3())
{}
example::Example getMessage() const
{
example::Example message;
populateMessage(message);
return message;
}
void populateMessage(example::Example& message) const
{
message.set_name(name_);
message.set_source(source_);
message.set_value_1(value_1_);
message.set_value_2(value_2_);
message.set_value_3(value_3_);
}
// Some example inspectors filled out...
std::string getName() const
{ return name_; }
uint32_t getSource() const;
{ return source_; }
uint32_t getDestination() const;
uint32_t getValue1() const;
uint32_t getValue2() const;
uint32_t getValue3() const;
// Some example mutators filled out...
void setName(const std::string& new_name)
{ name_ = new_name; }
void setSource(uint32_t new_source);
{ source_ = new_source; }
void setDestination(uint32_t new_destination);
void setValue1(uint32_t new_value);
void setValue2(uint32_t new_value);
void setValue3(uint32_t new_value);
private:
std::string name_;
uint32_t source_;
uint32_t destination_;
uint32_t value_1_;
uint32_t value_2_;
uint32_t value_3_;
};
这里没有可识别的"best practice"。我已经看到了很多这两种方式的例子,甚至看到了两种方式都有效的编写程序。有些人对此有很强的看法,但我认为这取决于用例。例如,正如您所说,如果您计划将大部分数据转发到另一台服务器,那么保留 protobuf 对象就很有意义。但其他时候你有更方便的内部表示——例如,在 protobufs 添加对地图的本地支持之前,如果你有一个将地图表示为 key/value 对的重复列表的 protobuf,你可能想要转换它提前 std::map
。