2015-05-14 161 views
3

對於C++中的協議緩衝區,我想知道是否最好在我的類中包含protobuf消息,或者讓它構建並填充外部protobuf信息。C++類應該包含協議緩衝區消息還是從協議緩衝區消息構建/填充

我找不到描述此案例最佳實踐的示例。我特別擔心兩種設計之間的性能差異。

在我的處理過程中,我將遇到一些情況,我將只從我的消息中讀取幾個字段,然後將消息路由到另一個進程(可能在發送消息之前操作消息)以及其他情況我的對象將有很長的生命週期,並被重新序列化之前使用很多次。在第一種情況下,我可能直接對protobuf消息進行操作,甚至不需要我的課程,而是將其放入現有的界面中。

下面是一個例子消息:

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 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_; 
}; 

+1

這個問題的大部分答案都是基於意見的。無論如何,另一個考慮因素是驗證和安全性。如果您直接從緩衝區構建類,則需要自己完成此操作(假設緩衝區可能來自不受信任的源),而如果您只是將其交給另一個組件,則可以讓消費組件擔心關於它。 – MooseBoys

+0

幾乎所有使用「最佳實踐」一詞的問題都可能被視爲基於意見的問題。 – Barmar

+0

我想我將它留給協議緩衝區來處理原始緩衝區的構造。或者我應該更關心協議緩衝區本質上是不安全的? – korhadris

回答

1

沒有公認的 「最佳實踐」 在這裏。我已經看到了大量的兩個例子,甚至是兩種方式的書面程序。有些人對此有非常強烈的意見,但在我看來,這取決於用例。例如,如你所說,如果你打算將大部分數據轉發到另一臺服務器,那麼保留protobuf對象就很有意義。但其他時候,您有更方便的內部表示形式 - 例如,在protobufs添加對地圖的本機支持之前,如果您有一個protobuf將地圖表示爲重複的鍵/值對列表,則可能需要將其轉換爲預先準備好了std::map

+0

瞭解了您與GPB和Cap'n Proto所做的所有工作,很高興知道這兩種情況都存在。我原本擔心我在這裏偏離軌道。謝謝。 – korhadris