2012-08-02 66 views
8

我在客戶端 - 服務器體系結構中使用協議緩衝區作爲有線數據格式。域對象(java bean)將經歷以下生命週期。協議緩衝區和OO設計

  1. ,用於客戶端業務邏輯
  2. 轉換爲protobuf的格式
  3. 傳輸到服務器
  4. 轉換回用於服務器端業務邏輯域對象

"Protocol Buffers and O-O Design" ProtoBuf文檔中的部分建議將生成的類包裝在適當的域模型中。

我想找出最好的選擇。

例如,我有一個簡單的原型定義。

package customer; 

option java_package = "com.example"; 
option java_outer_classname = "CustomerProtos"; 

message Customer { 
    required string name = 1; 
    optional string address = 2; 
} 

這就是域模型的定義方式。如您所見,數據完全存儲在原始生成器對象中。

package com.example; 

public class CustomerModel 
{ 
    private CustomerProtos.Customer.Builder builder = CustomerProtos.Customer.newBuilder(); 

    public String getName() 
    { 
     return builder.getName(); 
    } 

    public void setName(String name) 
    { 
     builder.setName(name); 
    } 

    public String getAddress() 
    { 
     return builder.getAddress(); 
    } 

    public void setAddress(String address) 
    { 
     builder.setAddress(address); 
    } 

    public byte[] serialize() 
    { 
     return builder.build().toByteArray(); 
    } 

} 

這是一個很好的做法嗎?因爲這些對象用於生命週期的所有階段,但我們只需要在客戶端 - 服務器傳輸階段使用protocolbuf格式。

當原型定義非常複雜且嵌套時,在訪問原型構建器類getter/setter方法時是否存在性能問題?

回答

5

我沒有協議緩衝區的經驗,但我會而不是建議實現您的域對象爲特定的序列化/傳輸框架定製。你可能會後悔的。

軟件應用程序的領域對象和邏輯應儘可能獨立於特定的實現問題(在您的案例序列化/傳輸中),因爲您希望您的領域在未來易於理解並可重複使用/可維護。

如果要定義你的域對象的獨立序列化/轉移的,你有兩個選擇:

  1. 系列化/轉讓之前,將信息複製到協議 緩衝區特定的對象,並將它們發送到您的服務器。那你 將不得不將信息複製回你的域對象。
  2. 使用非協議序列化庫(如KryoProtoStuff)將域對象直接轉移到 服務器。

選項1的缺點是您的域被定義了兩次(這對於修改是不可取的)和信息的複製(這產生了容易出錯和不可維護的代碼)。

選項2的缺點是你丟失了schema evolution(儘管ProtoStuff顯然爲supports it)並且完整(可能是大的)對象圖被序列化和傳輸。儘管可以在序列化/傳輸之前修剪對象圖(手動或使用JGT)。

2

我們制定了一個protobuf-converter來解決將您的域模型對象轉換爲Google Protobuf消息的問題,反之亦然。

如何使用它:

  • 類必須由@ProtoClass標記 annotaion包含 :

    必須被轉化爲protobuf的消息必須滿足下列條件:領域模型類有關protobuf消息類的參考。

  • 類字段必須標註@ProtoField註釋。這些字段必須有getter和setter。

例如:

@ProtoClass(ProtobufUser.class) 
public class User { 

    @ProtoField 
    private String name; 
    @ProtoField 
    private String password; 

    // getters and setters for 'name' and 'password' fields 
    ... 
} 

代碼轉換User實例成相關的protobuf消息:

User userDomain = new User(); 
... 
ProtobufUser userProto = Converter.create().toProtobuf(ProtobufUser.class, userDomain); 

代碼向後轉換:

User userDomain = Converter.create().toDomain(User.class, userProto); 

對象列表的轉換是類似於單個對象轉換。