Upcasting the downcasted object back in protobuffe

2019-09-06 07:38发布

问题:

Below is the proto code,

message Animal {
    optional string name = 1;
    optional int32 age = 2;  
}    

message Dog{
    optional string breed = 1;
}

Then the sample class using the above proto

public class InheritanceTest {

    public static void main(String[] args){
        Dog dog = Dog.getDefaultInstance();
        printAnimalName(dog.getAnimal());
    }

    public static void printAnimal(Animal animal){
        Dog dog = (Dog)animal; // Not at all possible right!
    }

} 

Is up-casting possible only by having an instance of dog as "required" in animal? or Is there any other way of upcasting?

回答1:

First, to be clear: "Upcasting" means casting a Dog to an Animal. "Downcasting" means casting an Animal to a Dog. Your question is about how to upcast, but your example appears to be about downcasting. I'll try to answer both.

In my answer to your other question, I presented three options for emulating inheritance with protobufs.

Option 1 makes upcasting easy but does not allow for downcasting.

Options 2 and 3 make downcasting possible, but do not support upcasting.

If you need to be able to both upcast and downcast, then you need to use option 2 or 3, but always pass around an Animal as simply an Animal. That is, if you have a function which only works on Dog, but needs to access some of the members of Animal as well, it must take Animal as its argument. The function's documentation should state that even though the argument type is Animal, the argument must have the dog field (or extension) set, i.e. it must actually be a Dog. You should throw an IllegalArgumentException otherwise.

Editorial: I know this is not a very satisfying answer. Protocol Buffers does not implement true inheritance because we couldn't come up with any design that seemed reasonable. The requirements of backwards- and forwards-compatibility on the wire make this problem a lot more complicated than it may seem. In practice, though, we've found that inheritance is rarely actually what you want anyway, and one of the options I presented usually works fine. In my opinion, inheritance makes sense for interfaces (i.e. collections of methods with behavior), but not for messages (i.e. collections of fields containing simple data).