zoukankan      html  css  js  c++  java
  • 最近重构一个通讯系统 想了一个很有趣的设计模式,我就叫——移花接木

     

    最近在重构通讯系统,最难处理的就是传输协议。一个普通的系统,最核心的协议也最少有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)之后,只要这个模板足够强大,那么日后我可以扩展出任意的协议,但是却不需要修改原来的解析引擎了。

     

    不知道大家觉得怎么样?

  • 相关阅读:
    HDOJ_就这么个烂题总是WA先放这把
    [NYLG-OJ] 77 开灯问题(白书例题)
    [NEUQ-OJ] 1012 SZ斐波拉契数列
    福尔摩斯到某古堡探险
    第n个素数是多少?
    自然数的和之和
    水仙花数
    解决满屏显示问题的css样式:object-fit
    H5新属性audio音频和 video视频的控制
    用indexOf方法来去重
  • 原文地址:https://www.cnblogs.com/zc22/p/1730821.html
Copyright © 2011-2022 走看看