Inheritance 如何使用proto缓冲区有效地完成继承

Inheritance 如何使用proto缓冲区有效地完成继承,inheritance,protocol-buffers,Inheritance,Protocol Buffers,我有一个基类消息 message Animal { optional string name = 1; optional int32 age = 2; } 以及扩展了animal的子类 message Dog{ optional string breed = 1; } 因此,在建立一条狗的信息时,我应该能够设置动物的所有领域。我知道这样做的方法(在狗的信息中再次声明所有的动物领域),但它是否可以简单有效地使用原型缓冲区? 此外,我还了解了扩展,我知道它只是用

我有一个基类消息

message Animal {
     optional string name = 1;
     optional int32 age = 2;  
}
以及扩展了animal的子类

message Dog{
     optional string breed = 1;
}
因此,在建立一条狗的信息时,我应该能够设置动物的所有领域。我知道这样做的方法(在狗的信息中再次声明所有的动物领域),但它是否可以简单有效地使用原型缓冲区? 此外,我还了解了扩展,我知道它只是用来向已经存在的消息添加一个新字段,因此不应将其误解为实现继承的可能解决方案


使用protobuffers的扩展是否可以实现上述简单设计?

在协议缓冲区中实现“继承”有几种不同的方法。您想要哪一个取决于您的用例

选项1:子类包含超类 这里,
Dog
包含一个
Animal
,因此包含
Animal
的所有信息

如果您不需要支持向下转换,则此方法有效。也就是说,您不必说“这是
动物
?”因此,任何可能需要访问
字段的内容都需要将
作为其输入,而不是
动物
。对于许多用例来说,这很好

选项2:超类包含所有子类 在这种方法中,给定一个
动物
,您可以找出它是哪种动物并访问特定物种的信息。也就是说,你可以投下

如果您有一个固定的“子类”列表,那么这种方法很有效。只需列出所有字段,并记录只应填写其中一个字段。如果有很多子类,您可能需要添加一个枚举字段来指示存在哪个子类,这样您就不必单独检查
has_dog()
has_cat()
has_mouse()

备选案文3:延期 该选项实际上在语义上与选项2相同!唯一的区别是,您没有在
Animal
中声明许多可选字段,而是将它们声明为扩展。每个扩展名都会有效地向
Animal
添加一个新字段,但您可以在其他文件中声明它们,因此您不必有一个中心列表,其他人也可以添加新的扩展名而无需编辑您的代码。由于每个扩展的行为就像一个常规字段,除了有一些奇怪的语法来声明和访问它之外,所有的行为都与选项#2相同。(事实上,在这里的示例中,导线编码甚至是相同的,因为我们使用100作为分机号,在选项2中,我们使用100作为字段号。)


这就是理解扩展的诀窍。许多人感到困惑,因为他们试图在面向对象语言中将“扩展”等同于继承。不要那样做!请记住,扩展的行为就像字段一样,这里的选项2和3实际上是相同的。这不是继承。。。但是它可以解决同样的问题。

它可能只是说了与您现有的解释相同的事情,但选项2(/3)能够满足LSP,并且能够处理版本之间出现的新子类,这也不值得,我怀疑这两个都只是“可以支持向下投射”的直接结果,尽管如此。@Kenton:向下投射能力正是我想要的,所以选择2就可以了。。thanks@MarcGravell例如我找不到你。什么是LSP?@aarish;基本上,如果代码需要一只
动物
,你可以给它一只
,它就会工作;在这种情况下,“给它一只狗”意味着“给它一只具有非空狗组件的动物”,除非您的protobuf实现具有实际的继承映射,使用Kenton描述的实现(我知道至少有一个实现是这样的;p)@aarish-使用选项2检查
动物
是否是
,只需调用
animal.hasDog()
。对于选项3,您必须说
animal.hasExtension(animalDog)
。您不需要使用描述符。
message Animal {
  optional string name = 1;
  optional int32 age = 2;  
}

message Dog {
  required Animal animal = 1;
  optional string breed = 2;
}
message Animal {
  optional string name = 1;
  optional int32 age = 2;

  // Exactly one of these should be filled in, depending on the species.
  optional Dog dog = 100;
  optional Cat cat = 101;
  optional Axolotl axolotl = 102;
  // ...
}
message Animal {
  optional string name = 1;
  optional int32 age = 2;
  extensions 100 to max;  // Should contain exactly one "species" extension.
}

message Dog {
  optional string breed = 1;
}

extend Animal {
  optional Dog animal_dog = 100;
  // (The number must be unique among all Animal extensions.)
}