Как правильно сделать полиморфизм с буфером протокола? - PullRequest
49 голосов
/ 11 июня 2010

Я пытаюсь долгосрочно сериализовать кучу объектов, связанных сильной иерархией классов в Java, и я хотел бы использовать буферы протокола, чтобы сделать это из-за их простоты, производительности и простоты обновления.Тем не менее, они не обеспечивают большую поддержку полиморфизма.Прямо сейчас, способ, которым я обращаюсь с этим, состоит в том, чтобы иметь решение «одно сообщение, чтобы управлять ими всеми», которое имеет обязательное поле строкового uri, которое позволяет мне создавать экземпляр правильного типа через отражение, а затем множество дополнительных полей для всехдругие возможные классы, которые я мог сериализовать, только один из которых будет использоваться (в зависимости от значения поля uri).Есть ли лучший способ справиться с полиморфизмом, или это так хорошо, как я собираюсь получить?

Ответы [ 7 ]

34 голосов
/ 02 марта 2016

В proto3 ключевое слово extend заменено. Из документов : If you are already familiar with proto2 syntax, the Any type replaces extensions.

syntax = "proto3";

import "google/protobuf/any.proto";

message Foo {
  google.protobuf.Any bar = 1;
}

Но будьте осторожны: Any по сути является байтовой каплей. В большинстве случаев лучше использовать Oneof:

syntax = "proto3";

message A {
    string a = 1;
}

message B {
    string b = 1;
}

message Foo {
  oneof bar {
    A a = 1;
    B b = 2;
  }
}
33 голосов
/ 03 ноября 2011

Существует несколько методов реализации полиморфизма. Я пытаюсь охватить их все здесь: Полиморфизм буферного протокола

Мой предпочтительный подход использует вложенные расширения :

message Animal
{
    extensions 100 to max;

    enum Type
    {
        Cat = 1;
        Dog = 2;
    }

    required Type type = 1;
}

message Cat
{
    extend Animal
    {
        required Cat animal = 100; // Unique Animal extension number
    }

    // These fields can use the full number range.
    optional bool declawed = 1;
}

message Dog
{
    extend Animal
    {
        required Dog animal = 101; // Unique Animal extension number
    }

    // These fields can use the full number range.
    optional uint32 bones_buried = 1;
}
15 голосов
/ 24 апреля 2015

Это не ответ на оригинальный вопрос, но может быть полезно для других, использующих v3 из Protocol Buffers . Версия 3 запрещает ключевое слово extensions. Запуск protoc в следующем файле приводит к ошибке с сообщением Extension ranges are not allowed in proto3.

syntax = "proto3";

message BaseMessage {
  extensions 100 to max;
}
5 голосов
/ 06 мая 2012

Решение Джона верное и работает, но довольно странно (для меня).Но Protocol Buffers довольно прост, поэтому вы можете сделать что-то вроде этого:

enum Type {
    FOO = 0;
    BAR = 1;
  }

message Foo {
  required Type type = 1;
}

message Bar {
  required Type type = 1;
  required string text = 2;
}

По сути, панель сообщений расширяет сообщение Foo (с практической стороны, конечно).Реализация в Java также проста:

Bar bar = Bar.newBuilder().setType(Type.BAR).setText("example").build();
byte[] data = bar.toByteArray();

----

Foo foo = Foo.parseFrom(data);
if(foo.getType() == Type.BAR){
   Bar bar = Bar.parseFrom(data);
   System.out.println(bar.getText());
}

Я знаю, это не элегантное решение, но оно простое и логичное.

2 голосов
/ 11 июня 2010

Ознакомьтесь с Расширениями и вложенными расширениями , чтобы получить более чистый способ сделать это.

0 голосов
/ 01 октября 2015

Для меня решение немного лучше, чем ответ @ Łukasz Marciniak.

Если Bar расширяет Foo, просто напишите:

message Bar {
   optional Foo foo = 1;
   optional double aDouble = 2;
}
message Foo {
   optional string aString = 1;
}

Так что, если Foo развивается, только сообщение Foo будетмодифицировано.

0 голосов
/ 11 июня 2010

Рассматривали ли вы использование расширений ?Вы можете сделать так, чтобы ваше поле uri определяло тип для использования, а затем просто загрузить соответствующие расширения.Если вы знаете, что ваши поля являются взаимоисключающими, то вы можете повторно использовать идентификатор поля между отдельными расширениями.

Вы должны обрабатывать все это самостоятельно, потому что буферы протокола не предназначены для самоописания, кроме простого списка значений.Об этом говорится на странице методов Google.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...