XMPP Framework是一个百宝箱,Robbie Hanson 是一个怪兽级别的程序员。

消息与业务对象的互相转化是一个累活

我们基于XMPP Framework做业务封装,我们必须要处理业务对象和消息的互相转化。我们自定义的协议为每一种消息扩充了不同的节点(XML),这其中,有两种消息我们共用一个节点,因此,这个节点里的信息的差异,我们都要解析,另外在单聊和群聊的基础上我们还划分了一个讨论组类型,but 这个讨论组类型并不像chat和groupchat那么容易得到,它又隐藏在一个单独的扩充节点里面用bool值去区分,因此这种转化是一个疲累的活。

让我们学习Robbie Hanson,如何处理累活

直接面对协议,一个节点一个节点的转,是繁琐不堪的。我们面对的问题是如何将我们自定义的协议,用oc对象的方式去处理。就像json转model,熟以习常的面向模型去开发。其实这种思路转换并不容易,程序员容易只见树木不见森林,很难跳出自己的安全区。XMPP框架就是实现协议的代码,Robbie Hanson是一个杰出的程序员,让我们学习他的处理方式。XMPP协议是基于XML格式便签来传递信息,在官方协议里面最常见的是三个标签节点,分别为<message></message>、<iq></iq>、<present></present> . Robbie Hanson针对这三种协议设计了三个类。我们可以在Framework的core找到。

XMPPElement XMPPMessage XMPPIQ XMPPPresent

其中XMPPElement是他们的基类。让我们体会下面的这种对比。

<message type="chat" to="xiaoming@example.com">  
  <body>Hello World!<body />  
<message />  

让我们来看结点的对应类的映射

@interface XMPPMessage XMPPElement  
...  
- (NSString *)type;  
- (NSString *)subject;  
- (NSString *)body;Hello World!  
- (NSString *)bodyForLanguage:(NSString *)language;  
- (NSString *)thread;  
...  
@end  

现在,我们获取某个节点的值,完全是面向对象,虽然NSXMLElement也是对象,但是XMPPMessage更加面向模型。例如,获取type、body,我们直接

message.type  或者 [message type]  
message.body 或者 [message body]

有了这样的对比,我们顿时就清楚了。比如我们为我们的消息类型扩充了一个location节点

 <location xmlns = “xxxx”>  
       <longitude> xxx </longitude>         
       <latitude>xxx </latitude>  
       <adress> xxx </adress>  
          ....  
 </location>  

那么我们可以这样用类来描述

@interface LocationElement : XMPPElement
@property (nonatomic, copy) NSString *longitude;
@property (nonatomic, copy) NSString *latitude;
@property (nonatomic, copy) NSString *city;
@end

即使我们自定义的节点,携带的信息非常多,我们也可以从容的去处理。

最后我们为XMPPMessage类,增加了一个分类,方便从XMPPMessage获取我们自定义的子节点

@interface XMPPMessage (SETransfer)
- (BOOL)isMessageWithFile;
- (FileInfoElement*)fileInfoElement;
....
- (BOOL)isMessageWithLocation;
- (LocationInfoElement*)locationInfoElement;
....
@end

当然,我们对业务对象,也做了类似的处理。这样我们就比较容易的完成了消息与业务对象互相转化的累活。

补充: 我们运用runtime,动态的业务对象添加了方法。