回应老赵: 适合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的消息)即可。

 


  public interface IMessageRouter:IEnumerable<KeyValuePair<Key,ISubject>>
    {
        
string Name { getset; }

        ISubjectBuilder Builder { 
get;}
        IHookManager HookManager { 
get;}
        IDelegateInvoker DelegateInvoker { 
get;}

        
bool ContainSubject(Type type);
        
bool ContainSubject(string topic, Type type);
        
bool ContainSubject<T>();
        
bool ContainSubject<T>(string topic);

        ISubject[] Items { 
get; }
        ISubject
<TMessage> Subject<TMessage>();
        ISubject
<TMessage> Subject<TMessage>(string 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 定义:

 


    class Topics
     {
        
public const string Ping = "Topic://PingPongTest/Ping";
        
public const string Pong = "Topic://PingPongTest/Pong";
     }

 

消息类:就用Int类型

Ping 类的实现代码:

 


       class Ping
        {
            
int m_count = 5;
            
public Ping()
            {
                Actor.Receive
<int>(Topics.Pong, (s, e) =>
                {
                    Console.WriteLine(
"Ping received pong :" + e.Message);

                    
if (--this.m_count > 0)
                    {
                        Console.WriteLine();
                        Console.WriteLine(
"Ping sent  :" + m_count.ToString());
                        Actor.Post
<int>(Topics.Ping, m_count);
                    }
                    
else
                    {
                        Console.WriteLine(
"Finished");
                        Actor.Exit
<Ping>(Topics.Ping);
                    }
                });
            }

            
public void Start()
            {
                Console.WriteLine(
"Ping sent  :" + m_count.ToString());
                Actor.Post
<int>(Topics.Ping, m_count);
            }
        }

 

 

Pong 类的实现非常简单:

 


    class Pong
        {
            
public Pong()
            {
                Actor.Receive
<int>(Topics.Ping, (s, e) =>
                {
                    Console.WriteLine(
"Pong received ping :" + e.Message.ToString());
                    Console.WriteLine(
"Pong sent  :" + e.Message.ToString());
                    Actor.Post
<int>(Topics.Pong, e.Message);
                });
            }
        }

 

测试代码:

 

       [Test]
        
public void Test()
        {
            var ping 
= new Ping();
            var pong 
= new Pong();
            ping.Start();
        }

 

程序输出:

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,暂时先写到这里,欢迎大家一起进行交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值