Наследование в буферах протоколов

Как обрабатывать наследование в Google Protocol Buffers 3.0?

Java-эквивалентный код:

public class Bar {
    String name;
}
public class Foo extends Bar {
    String id;
}

Какой будет эквивалентный код Прото?

message Bar {
    string name = 1;
}
message Foo {
    string id = 2;
}

Ответ 1

Буферы протокола не поддерживают наследование. Вместо этого рассмотрите возможность использования композиции:

message Foo {
  Bar bar = 1;
  string id = 2;
}

Тем не менее, это говорит о трюке, который вы можете использовать, который похож на наследование, но который является уродливым взломом, поэтому вы должны использовать его только с осторожностью. Если вы определяете свои типы сообщений, например:

message Bar {
  string name = 1;
}
message Foo {
  string name = 1;
  string id = 2;
}

Эти два типа совместимы, поскольку Foo содержит надмножество полей Bar. Это означает, что если у вас есть закодированное сообщение одного типа, вы можете декодировать его как другой тип. Если вы попытаетесь декодировать Bar как тип Foo, id поля не будет установлен (и получит значение по умолчанию). Если вы декодировать Foo как тип Bar, поле id будет игнорироваться. (Обратите внимание, что это те же правила, которые применяются при добавлении новых полей к типу с течением времени.)

Вы можете использовать это для реализации чего-то вроде наследования, имея несколько типов, все из которых содержат копию полей "суперкласса". Тем не менее, есть пара больших проблем с этим подходом:

  • Чтобы преобразовать объект сообщения типа Foo в тип Bar, вы должны сериализовать и повторно разобрать; вы не можете просто бросить. Это может быть неэффективным.
  • Очень сложно добавить новые поля в суперкласс, потому что вы должны обязательно добавить поле в каждый подкласс и должны убедиться, что это не создает конфликтов номера поля.