最近重构一个通讯系统 想了一个很有趣的设计模式,我就叫——移花接木

 

最近在重构通讯系统,最难处理的就是传输协议。一个普通的系统,最核心的协议也最少有10多种。

 

我自然会使用面向对象去做,而不是用StringBuilder之类的去拼、去解析。

 

按照普通的面向对象思路,有两种方案:

 

1. 第一个失败方案:每个协议一个对象,例如:

 

代码
        interface IAddContact
        {
            
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. 第二个失败方案是使用一个总的对象,他包含了所有协议使用的字段:

 

代码
    public interface IMessageflowMessage : IMessage
    {
        
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种方案,具体如下:

 

代码
interface IMessageflowMessage
{
    
//这是个协议模板 可能包含了上百种属性字段
    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这个字段,其他字段都被“屏蔽”了。

 

最后,我为什么叫这个是移花接木呢?很简单,我调用的代码是:

 

string message = "xxxxxxxxxxxxxxx";
IAddContact protocol = Deserialize<AddContact>(message);

首先对传入的字符串协议,反序列化为AddContact对象,然而这个对象本身没有任何代码,都是继承了MessageflowMesasge。

 

其次,这个AddContact对象又会被我以IAddContact接口形式返回,这样逻辑上就出现了一个非常有趣的现象:

协议模板和我返回的接口在代码上是没有任何关系的(MessageflowMessage / IMessageflowMessage 和 IAddContact);但是他们通过了一个空的类(AddContact)联系在了一起,因此被移花接木了!

 

这种设计模式下,我只要规定了协议模板(MessageflowMessage)之后,只要这个模板足够强大,那么日后我可以扩展出任意的协议,但是却不需要修改原来的解析引擎了。

 

不知道大家觉得怎么样?

原文地址:https://www.cnblogs.com/zc22/p/1730821.html