巧用消息驱动解耦功能模块之间的复杂关系

        不知各位看官遇到开发大型系统的时候,往往功能模块之间都有理不清的复杂关系,例如MES中的生产进度,ERP中的物品流向,单据的处理流程变更,库存的变更等等,很多时候,都是需要模块之间协作才能更好的简化数据处理,靠关联性查询来找结果,难度很大的,说白了就是要把复杂的关系数据,冗余到相关各相关模块中,把错综复杂的关系数据砍断。

        做系统的时候,设计功能的时候,相互都存在一定方向的调用关系的,例如员工模块是不会去调用业务模块的,例如要删除一个员工,要查询是否与业务数据产生了关联关系,如果删掉了,就会导致查询时候缺失了这个员工的信息,可能影响到部门的业绩数据。那么怎么才能判断是否可以删除员工数据呢?

        消息驱动机制,可以简单理解成一个大喇叭,发生了什么时候,喊一下,全场都听到了,至于听到之后,是否要处理,那就是自己的事情了。注意,发出去的消息必须是单向的,不能设计成API的等待返回模式。

        看了很多第三方开发的框架,都有类似MessageCenter的类,但是都有一个特点,不知道是不是我理解有问题了,先说说。发布消息基本都是一个模式:

        Send(string topic,T data);

        订阅的一方基本都是

        MessageCenter.Consume(string topic,Action action);

        订阅的时候,要执行这么个订阅方法,否则就不能收到消息。但是,如果一个模块没有启动过,是不是可以认为,这个模块就会丢失消息了呢?起码我是这么认为的。

        其实我是不希望程序员知道有个MessageCenter类的,总感觉给程序员知道太多,可控性就约差。于是,就专门做了一个插件,起了个简单的名字,IMHelper.这里封装了发布和订阅的方法,原理其实很简单,就是比传统的MessageCenter多了一个启动器,让我慢慢道来。

        发布消息都没有问题,主要是订阅这部分,具体使用如下:

       

[IMConsume("StoreChanged")]
public void DoStoreChanged(StoreEventArgs args)
{
    //处理库存变化后的消息
}

在程序启动的时候,加载一个消息转发类,命名为IMStarter,例如在Framework中,放到Application_Start()事件中加载。这个类一旦启动,就收集带有IMConsume标签的类和方法,产生一个List列表, 找这么个列表,当然通过反射实现了,不一一说明了。

        public class consumeInfo

        {

                public MethodInfo method {get;set;}

                public string Topic{get;set;}

        }

        注意,同一个主题可能会有多个方法订阅的,所以不能做成key\value的数据结构。

        IMStarter另外一个功能就是就是接收所有发送出来的消息,然后根据topic来寻找到对应的方法,然后把消息传递到方法中:MethodInfo.Invoke(),由于是单向的,发布一方是不理会返回结果,这里完全可以使用线程来加快处理方法:

        Task.Run(()=>{method.Invoke(....)});

        其实之前也写过类似的内容,只不过是微服务之间的通知,原理都是一样的,一个是从MQ中接收消息然后转发,一个是从内存中接收消息,然后转发。

        这样使用消息驱动的好处就是,当某一个模块去掉了,也不影响现有模块的运行,设置一个订阅者都没有也没有关系,对于日后项目的迁移或者变更,大大降低了代码修改的麻烦事,还是坚持面向对象的原则,自己的事情自己干,不要总想着伸手要数据。不要想着偷懒实现功能就算了,否则日后的维护难度就大大增加。

        用消息驱动,还为插件化开发提供了非常便利的解决方案,甚至动态增加一个库文件,系统也能顺利调用并正确运行,系统就具有了很好的扩展性。

你可能感兴趣的:(c#,数据结构)