庄子与惠子游于濠梁之上。
庄子曰:“儵鱼出游从容,是鱼之乐也。”
惠子曰:“子非鱼,安知鱼之乐?”
庄子曰:“子非我,安知我不知鱼之乐?”
惠子曰:“我非子,固不知之矣;子固非鱼也,子之不知鱼之乐,全矣。”
庄子曰:“请循其本。子曰‘汝安知鱼之乐’云者,既已知吾知之而问我,我知之濠上也。”
以上剧本使用委托实现:
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了