• 回应老赵: 适合C# Actor的消息执行方式 中看也中用的解决方案


      

      今天粗粗看了老赵的文章适合C# Actor的消息执行方式 -中看不(3):中用的解决方案,我在想如果用我以前写的消息总线来实现那不是中看也中用了,于是顺手写了一个测试代码(具体内容参见适合C# Actor的消息执行方式 -中看不(3):中用的解决方案回复),说来很惭愧我的消息总线系列已经一年多没有更新了,我这人太懒散惯了,没办法。废话不多说了,下面我就具体讲解一下设计思路。

      在Actor模式中,最重要的就是Actor间的消息发送以及消息路由了。

      消息发送:举一个例子实现一个ActorA向ActorB发消息,最简单的方法就是:ActorA中需要内聚或依赖一个ActorB对象,然后就可以直接发消息通讯了,这种方法优点不言而喻-简单,但是当一个系统中存在无数个Actor,一个Actor有可能向N多的其它Actor发消息,这种方法的弊端就暴露无疑了:强依赖,强耦合。 怎么结局这种问题呢,这时候设计模式中的中介者模式就可以派上用场了。所有的Actor都向中介者发消息即可,由中介者把消息通过一定的策略路由到特定的Actor,由这个特定的Actor进行处理即可。

      消息路由:消息路由的关键就是路由表,路由表可以用字典来实现,Key-可以用消息类型+Topic来标记即可,Value :就用委托函数即可。

    具体简略设计图如下:

    类图详解:

        ISubject<TMessage>代表Actor,该接口继承了IPublisher接口,同时定义了Observers事件,典型的观察者模式,所以该接口具有发布和订阅消息的功能。

             

     

      //发布器接口
       
    public interface IPublisher
        {
            
    void Publish(object sender, object msg);
        }

        
    public interface IPublisher<TMessage> : IPublisher
        {
            
    void Publish(object sender, TMessage msg);
        }

        //Actor 接口
        
    public interface ISubject:IPublisher
        {

            //发布消息的Topic名称
            
    string Name { getset; }
            
    void Close();//退出,从消息总线中移除该Topic的Actor
        }

        
    public interface ISubject<TMessage> : ISubject,IPublisher<TMessage>
        {

           //观察者集合
            
    event ObserverHandler<TMessage> Observers;

            //消息订阅者
            ISubscriber
    <TMessage> Subscriber { getset; }
            

            //消息队列
            IQueue
    <KeyValuePair<object,TMessage>> Queue { getset; }

           //消息执行器
            IExecutor
    <TMessage> Executor { getset; }

            
    bool Closed { get; }
        }

                IMessageRouter 内聚了ISubject(Actor)的字典,Actor的消息发送以及消息接收的重担全部都交给了IMessageRouter,使Actor和Actor之间不需要知道对方的存在,Actor只需要发布消息(或基于Topic的消息)即可,或者只需要接受消息(或基于Topic的消息)即可。

            //Delete Subject by Message Type or Topic
            
    void Remove<TMessage>();
            
    void Remove<TMessage>(string topic);
            
    void Remove(Type type);
            
    void Remove(string topic, Type type);

           //订阅消息-注册观察者
            
    void Subscribe<TMessage>(ObserverHandler<TMessage> handler);
            
    void Subscribe<TMessage>(string topic, ObserverHandler<TMessage> handler);
            
    void Subscribe<TMessage>(object observer, ObserverHandler<TMessage> handler);
            
    void Subscribe<TMessage>(string topic,object observer, ObserverHandler<TMessage> handler);
            //移除订阅者
            
    void Unsubscribe<TMessage>(ObserverHandler<TMessage> handler);
            
    void Unsubscribe<TMessage>(string topic, ObserverHandler<TMessage> handler);
            
           //订阅前置过滤器消息 - 注册前置过滤器观察者
            
    void SubscribePreFilter<TMessage>(PreFilterHandler<TMessage> handler);
            
    void SubscribePreFilter<TMessage>(string topic, PreFilterHandler<TMessage> handler);
            
    void SubscribePreFilter<TMessage>(object sender, PreFilterHandler<TMessage> handler);
            
    void SubscribePreFilter<TMessage>(string topic, object sender, PreFilterHandler<TMessage> handler);

            
    void UnsubscribePreFilter<TMessage>(PreFilterHandler<TMessage> handler);
            
    void UnsubscribePreFilter<TMessage>(string topic,PreFilterHandler<TMessage> handler);
            
           //注册过滤器消息 - 注册过滤器观察者
            
    void SubscribeFilter<TMessage>(FilterHandler<TMessage> handler);
            
    void SubscribeFilter<TMessage>(string topic, FilterHandler<TMessage> handler);
            
    void SubscribeFilter<TMessage>(object observer, FilterHandler<TMessage> handler);
            
    void SubscribeFilter<TMessage>(string topic, object observer, FilterHandler<TMessage> handler);

            
    void UnsubscribeFilter<TMessage>(FilterHandler<TMessage> handler);
            
    void UnsubscribeFilter<TMessage>(string topic, FilterHandler<TMessage> handler);


            
    int Count { get; }
           

            //注册钩子(钩子的部分函数也可充当消息过滤器使用)
            
    void RegisterHook(params IHook[] hooks);
            
    void UnRegisterHook(params IHook[] hooks);

           //发布消息
            
    void Publish<TMessage>(TMessage msg);

            void Publish<TMessage>(string topic, TMessage msg);//发布基于主题的消息
            
    void Publish<TMessage>(object sender, TMessage msg);
            
    void Publish<TMessage>(string topic, object sender, TMessage msg);//发布基于主题的消息


           //推荐方式:注册卸载发布基于主题的消息
            
    void SubscribeTopic<TMessage>(string topic, ObserverHandler<Topic<TMessage>> handler);
            
    void UnsubscribeTopic<TMessage>(string topic, ObserverHandler<Topic<TMessage>> handler);
            
    void PublishTopic<TMessage>(Topic<TMessage> topic);

            
    void Clear();
        }

         改进版的Ping/Pong, Ping和Pong互不依赖,它们之间仅仅通过Topic和消息类型作为标签进行通讯

    Topics 定义:

    消息类:就用Int类型

    Ping 类的实现代码:

    Pong 类的实现非常简单:

    测试代码:

    程序输出:

    Ping sent  :5
    Pong received ping :5
    Pong sent  :5
    Ping received pong :5


    Ping sent  :4
    Pong received ping :4
    Pong sent  :4
    Ping received pong :4


    Ping sent  :3
    Pong received ping :3
    Pong sent  :3
    Ping received pong :3


    Ping sent  :2
    Pong received ping :2
    Pong sent  :2
    Ping received pong :2


    Ping sent  :1
    Pong received ping :1
    Pong sent  :1
    Ping received pong :1
    Finished

    OK,暂时先写到这里,欢迎大家一起进行交流!

  • 相关阅读:
    兼容ie6:zindex
    分割网址/链接/url变量
    JS:给select添加option选项
    如果用QQ邮箱订阅一个网站或博客?
    input无边框
    有些标签的innerHTML属性是只读的
    满屏透明层
    文本框光标不居中?
    PHP:json_decode解析JSON数据
    开放平台/API
  • 原文地址:https://www.cnblogs.com/netcasewqs/p/1525492.html
Copyright © 2020-2023  润新知