运用委托是注意异步调用

庄子惠子游于濠梁之上。
  庄子曰:“儵鱼出游从容,是鱼之乐也。”
  惠子曰:“子非,安知鱼之乐?”
  庄子曰:“子非我,安知我不知鱼之乐?”
  惠子曰:“我非子,固不知之矣;子固非鱼也,子之不知鱼之乐,全矣。”
  庄子曰:“请循其本。子曰‘汝安知鱼之乐’云者,既已知吾知之而问我,我知之濠上也。”

以上剧本使用委托实现:

1. 主控模块

class Program
    {
        static void Main(string[] args)
        {
            Robot.Common.AncientRobot 庄子 = null;
            Robot.Common.AncientRobot 惠子 = null;
            Robot.Common.ModernRobot 解说员 = null;

            庄子 = new Robot.Common.AncientRobot("庄子");
            惠子 = new Robot.Common.AncientRobot("惠子");
            解说员 = new Robot.Common.ModernRobot("解说员");
            
            庄子.Observe(惠子);
            
            惠子.Observe(庄子);

            解说员.Observe(庄子);
            解说员.Observe(惠子);
            
            庄子.Speak("儵鱼出游从容,是鱼之乐也。");
        }
    }

2. 业务模块

public abstract class Robot
    {
        public delegate void delegAction(object sender, string msg);

        public event delegAction action;
        public string Id;

        public Robot(string id)
        {
            this.Id = id;
        }
        public virtual void Listen(object sender, string msg)
        {
            string newMsg = ThinkThenSay(msg);
            if (newMsg != null)
            {
                Speak(newMsg);
            }
        }

        public abstract string ThinkThenSay(string msg);
        public void Speak(string msg) 
        {
            System.Console.WriteLine(this.Id + ": " + msg);
            CallObserver(msg);
        }
        private void CallObserver(string newMsg)
        {
            if (this.action != null)
            {
                action(this, newMsg);//
            }
        }
        public void Observe(Robot obj) 
        {
            obj.action += this.Listen;
        }
    }

    public class AncientRobot:Robot
    {
        public AncientRobot(string id):base(id)
        {
        }
        public override string ThinkThenSay(string msg)
        {
            System.Threading.Thread.Sleep(1000 * 1);
            string newMsg = null;
            if (msg == "儵鱼出游从容,是鱼之乐也。")
            {
                newMsg = "子非鱼,安知鱼之乐?";
            }
            else if (msg == "子非鱼,安知鱼之乐?")
            {
                newMsg = "子非我,安知我不知鱼之乐?";
            }
            else if (msg == "子非我,安知我不知鱼之乐?")
            {
                newMsg = "我非子,固不知之矣;子固非鱼也,子之不知鱼之乐,全矣。";
            }
            else if (msg == "我非子,固不知之矣;子固非鱼也,子之不知鱼之乐,全矣。")
            {
                newMsg = "请循其本。子曰‘汝安知鱼之乐’云者,既已知吾知之而问我,我知之濠上也。";
            }
            else
            {
            }
            return newMsg;
        }
    }

    public class ModernRobot : Robot
    {
        public ModernRobot(string id):base(id)
        {
        }
        public override string ThinkThenSay(string msg)
        {
            string newMsg = null;//我不说话
            return newMsg;
        }

        public override void Listen(object sender, string msg)
        {
            System.Console.WriteLine("(" + this.Id + "" + "听到" + (sender as Robot).Id + "消息了" + msg + ")");
            base.Listen(sender, msg);
        }
    }
 

这样貌似没啥问题,然并卵,运行结果

预期输出结果应该为图一,然而多次测试发现运行结果具有不定性,还会出现图二,图三,图四的情况(这并非我想要的结果)。

分析代码:

该程序采用订阅者模式,庄子和惠子都是发布者,他们相互监听,所以他们又是彼此的订阅者,至于第三者解说员,他同事监听庄子和惠子。

所以,庄子和惠子都有两个订阅者。

public void Observe(Robot obj) 
{
    obj.action += this.Listen;
}
public virtual void Listen(object sender, string msg)
{
    string newMsg = ThinkThenSay(msg);
    if (newMsg != null)
    {
         Speak(newMsg);
    }
}
public void Speak(string msg) 
{
     System.Console.WriteLine(this.Id + ": " + msg);
     CallObserver(msg);
}
private void CallObserver(string newMsg)
{
     if (this.action != null)
     {
         action(this, newMsg);//
     }
}

正是由于Listen——》Speak——》CallObserver——》Listen,这里是单线程执行,整个过程执行完后才允许执行其它订阅者的代码,所以不能按照我预期的代码路径走。由于这样像一个圆一样的消息流(这是由于前面 庄子.Observe(惠子);  惠子.Observe(庄子); 产生的圆形消息流),其它订阅者的订阅事件可以不定性地插入到该消息流中,所以输出的结果也会多样性。


3.最后

为了达到我预期的理想结果,订阅者的激活事件采用异步多线程,他的消息流就会是这样的Listen——》Speak, Listen——》Speak, ...

public virtual void Listen(object sender, string msg)
{
    new System.Threading.Thread(() =>
    {
        string newMsg = ThinkThenSay(msg);
        if (newMsg != null)
        {
            Speak(newMsg);
        }
     }).Start();
}
运行一下,结果就是图一的预期结果,OK了


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值