23

我在客户端-服务器架构中使用协议缓冲区作为有线数据格式。域对象(java bean)将经历以下生命周期。

  1. 用于客户端业务逻辑
  2. 转换为 protobuf 格式
  3. 传送到服务器
  4. 转换回域对象
  5. 用于服务器端业务逻辑

ProtoBuf 文档中的“协议缓冲区和 OO 设计”部分建议将生成的类包装在适当的域模型中。

我想找出最好的方法。

例如,我有一个简单的原型定义。

package customer;

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

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

这就是定义域模型的方式。如您所见,数据完全存储在 proto builder 对象中。

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格式。

访问 proto builder 类 getter/setter 方法时是否存在任何性能问题,特别是当 proto 定义复杂且嵌套时?

4

2 回答 2

16

我没有使用协议缓冲区的经验,但我建议实现为特定序列化/传输框架量身定制的域对象。你将来可能会后悔。

软件应用程序的域对象和逻辑应尽可能独立于特定的实现问题(在您的情况下是序列化/传输),因为您希望您的域易于理解并且将来可重用/可维护。

如果您想定义独立于序列化/传输的域对象,您有两种选择:

  1. 在序列化/传输之前,您将信息复制到协议缓冲区特定对象并将它们发送到您的服务器。在那里,您必须将信息复制回您的域对象。
  2. 使用KryoProtoStuff等非协议序列化库将您的域对象直接传输到服务器。

选项 1 的缺点是您的域被定义了两次(这对于修改来说是不可取的)和信息的复制(这会产生容易出错和不可维护的代码)。

选项 2 的缺点是您失去了模式演变(尽管 ProtoStuff 显然支持它)并且完整的(可能很大的)对象图被序列化和传输。尽管您可以在序列化/传输之前修剪对象图(手动或使用JGT )。

于 2013-05-03T13:51:18.550 回答
4

我们制作了一个protobuf 转换器来解决将域模型对象转换为 Google Protobuf 消息的问题,反之亦然。

如何使用它:

必须转换为 protobuf 消息的领域模型类必须满足条件:

  • 类必须由@ProtoClass注释标记,其中包含对相关 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);

对象列表的转换类似于单个对象的转换。

于 2016-05-11T09:29:15.700 回答