最近在重构通讯系统,最难处理的就是传输协议。一个普通的系统,最核心的协议也最少有10多种。
我自然会使用面向对象去做,而不是用StringBuilder之类的去拼、去解析。
按照普通的面向对象思路,有两种方案:
1. 第一个失败方案:每个协议一个对象,例如:
{
string Guid { get;}
string MessageId { get;}
string ConnectorIdentifier { get;}
string ReceiverCode { get;}
}
interface IBind
{
string Command { get;}
string Guid { get;}
string SenderName { get; }
string MessageId { get;}
MessageflowLevel LevelType { get;}
string ReceiverCode { get;}
string ReceiverName { get;}
string ConnectorIdentifier { get;}
}
可是这种方式的最恶心的地方在于,没有一个统一的基接口,导致处理逻辑复杂;一个协议就一个对象+一个接口。在系统中,当字符串被传递过来的时候,解析(反序列化)起来就非常麻烦。
比方说,有50%的协议使用了GUID,而另外50%的使用了MessageId等等。但是协议之间又无法提取公共的interface。那么实际的处理程序就需要一个个去判断反序列化了。超级恶心。
2. 第二个失败方案是使用一个总的对象,他包含了所有协议使用的字段:
{
string Command { get;}
MessageflowLevel LevelType { get;}
MessageflowCommand CommandType { get;}
string ConnectorIdentifier { get;}
string Guid { get;}
string Token { get;}
string MessageId { get;}
string ReceiverCode { get;}
string ReceiverName { get;}
string SenderName { get; }
string Message { get; }
string Serialize();
}
这个方案虽然可以对所有协议进行了统一的对象化,可是实际编码起来,我又发现了另外一个问题:由于不同的协议需要使用的字段不一样,那么一个处理模块可能仅仅需要10%的字段;这样我就发现我陷入了一个遗忘的陷阱,经常忘记某个协议的关键字段是什么。
虽然我可以通过写文档去帮助我开发,可是在不断修改的过程中,协议会经常变动,这样开发精力放在了2头(维护文档和代码),得不偿失。
于是我今天起床吃饭的时候,用了1个小时去思考,终于得到了一个设计模式——移花接木:
这个模式的特点是结合了2种方案,具体如下:
{
//这是个协议模板 可能包含了上百种属性字段
string GUID {get;set;}
string MessageID {get;set;}
}
class MessageflowMessage : IMessageflowMessage
{
//协议模板的具体实现类
public string GUID
{
get { return guid; } set { guid = value; }
}
public string MessageID
{
get { return messageId; } set { messageId = value; }
}
}
interface IAddContact
{
//这是个具体的协议,仅仅包含了少数的属性字段
string GUID {get;set;}
}
class AddContact : MessageflowMessage, IAddContact
{
//这个是某个具体协议接口的实现,要注意,这里实际上没有代码
}
就这么简单!!!在这超级漂亮的模式中,
首先,有个基本的协议模板,MessageflowMessage,他包含了所有的协议字段。
其次,具体要调用的协议 AddContact又继承了MessageflowMessage,因此这个class是不需要任何代码的。
再次,AddContact又继承了接口IAddContact,用户实际使用过程中,仅仅需要了解GUID这个字段,其他字段都被“屏蔽”了。
最后,我为什么叫这个是移花接木呢?很简单,我调用的代码是:
首先对传入的字符串协议,反序列化为AddContact对象,然而这个对象本身没有任何代码,都是继承了MessageflowMesasge。
其次,这个AddContact对象又会被我以IAddContact接口形式返回,这样逻辑上就出现了一个非常有趣的现象:
协议模板和我返回的接口在代码上是没有任何关系的(MessageflowMessage / IMessageflowMessage 和 IAddContact);但是他们通过了一个空的类(AddContact)联系在了一起,因此被移花接木了!
这种设计模式下,我只要规定了协议模板(MessageflowMessage)之后,只要这个模板足够强大,那么日后我可以扩展出任意的协议,但是却不需要修改原来的解析引擎了。
不知道大家觉得怎么样?