标签:
java中有多态的概念,protobuf本身没有多态的概念,但是它有一个扩展的概念。
以聊天消息为例,先看下面这个类图,基类是ChatMessage,子类TextMessage和ImageMessage。
ChatMessage
TextMessage
ImageMessage
父类ChatMessage的schema如下,其中声明了一个ContentType枚举,有两个值text和image,分别代表文本和图片,根据content_type可以获得扩展信息。
1 package polymorphism; 2 3 option java_package = "polymorphism"; 4 option java_outer_classname = "BaseChatMessageProtos"; 5 6 message ChatMessage { 7 optional string id = 1; 8 optional string from = 2; 9 optional string to = 3; 10 11 enum Type { 12 chat = 0; 13 groupchat = 1; 14 error = 2; 15 } 16 17 optional Type type = 4; 18 19 enum ContentType { 20 text = 0; 21 image = 1; 22 } 23 24 optional ContentType content_type = 5; 25 26 extensions 100 to 299; 27 }
子类TextMessage和ImageMessage的schema如下
1 package polymorphism; 2 3 option java_package = "polymorphism"; 4 option java_outer_classname = "ConcreteChatMessageProtos"; 5 6 import "polymorphism/base_chat_message.proto"; 7 8 message TextBody { 9 extend ChatMessage { 10 optional TextBody body = 100; 11 } 12 13 optional string content = 1; 14 } 15 16 message ImageBody { 17 extend ChatMessage { 18 optional ImageBody body = 101; 19 } 20 21 optional string url = 1; 22 }
根据schema生成的java类,参考protobuftest工程polymorphism包路径下的BaseChatMessageProtos类和ConcreteChatMessageProtos类。
protobuftest工程下载地址:http://pan.baidu.com/s/1jIGWBf4
下面是序列化和反序列化的代码
1-8行:构造文本消息
12行:获得序列化字节数组
14-16行:创建并初始化扩展注册中心
18行:反序列化获得ChatMessage
21-23行:生成contentType和Extension(消息内容扩展描述)的映射关系,方便反序列化时获得扩展信息body
28行:根据contentType获得对应的TextMessage扩展描述,然后获得TextBody中定义的body
1 ChatMessage textMessage = ChatMessage.newBuilder() 2 .setId("123") 3 .setFrom("100@pingan.com.cn") 4 .setTo("101@pingan.com.cn") 5 .setType(Type.chat) 6 .setContentType(ContentType.text) 7 .setExtension(TextBody.body, TextBody.newBuilder().setContent("hello world").build()) 8 .build(); 9 10 System.out.println("*****before serialize=" + textMessage); 11 12 byte[] bytes = textMessage.toByteArray(); 13 14 ExtensionRegistry registry = ExtensionRegistry.newInstance(); 15 registry.add(ImageBody.body); 16 registry.add(TextBody.body); 17 18 ChatMessage deserializedMessage = ChatMessage.parseFrom(bytes, registry); 19 System.out.println("*****after deserialize"); 20 21 Map<ChatMessage.ContentType, Extension<ChatMessage, ?>> contentType2ExtensionBody = new HashMap<ChatMessage.ContentType, Extension<ChatMessage, ?>>(); 22 contentType2ExtensionBody.put(ContentType.text, TextBody.body); 23 contentType2ExtensionBody.put(ContentType.image, ImageBody.body); 24 25 ContentType contentType = deserializedMessage.getContentType(); 26 switch (contentType) { 27 case text: 28 TextBody deserializedTextBody = (TextBody) deserializedMessage.getExtension(contentType2ExtensionBody.get(contentType)); 29 System.out.println("body=" + deserializedTextBody); 30 break; 31 case image: 32 ImageBody deserializedImageBody = (ImageBody) deserializedMessage.getExtension(contentType2ExtensionBody.get(contentType)); 33 System.out.println("body=" + deserializedImageBody); 34 break; 35 default: 36 break; 37 }
25-37行:根据contentType获取对应扩展信息的body。注意:可以使用多态消除case语句
以后每增加一种新的消息内容类型,在反序列化的时候只需要在contentType和Extenstion(消息内容扩展描述)的映射关系中新增一个映射,然后新增一个获取对应消息内容类型的body的子类,无需修改其他的代码。
标签:
原文地址:http://www.cnblogs.com/csusofttjl/p/5487616.html