烧水器事件簿 的简单实现
昨天看了Allen Lee写的一篇好文《烧水器事件簿 [Design, C#] 》。
不过由于本人学艺不精,看了好久才把握了它的工作流程。于是将他的代码作了小小改动并编写了一段测试代码对它进行了一个简单的实现:
1.在EnrollManager.cs中的Run()方法中增加了对Enrollee的Boil()方法的调用,让整个流程动作起来,同理也对MoveNext()作了改动,并加了两个WriteLine()显示,添加了IsProcessing属性反映是否有有人在使用Boiler,如果为真,则加信队列的人可直接由MoveNext()驱动,否则就要调用EnrollManager的Run()方法来驱动。
2.Enrollee.cs中将倒水时间设为1秒,然后加入了对Done()方法的调用。就是假设Enrolee完成倒水后就马上告诉EnrollManager,Boiler我用完了,你去分配它吧,即实现作者所说了Enrollee对Done()的手动调用。
3.Boiler.cs中增加了UserName属性,我觉得这很有必要,因为那些等待的人知道,现在谁在使用Boil。然后将烧水的时间提高到了4秒,呵呵,为了快点看到测试结果。
4.最后就是编写了事件模拟Program.cs:
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Proton;
class Test
{
private static EnrolleeManager em=new EnrolleeManager();
private static Boiler b=new Boiler();
public static void Main()
{
Enrollee e1=new Enrollee("Paul","room1",EnrolleePriority.High);
Enrollee e2=new Enrollee("Henry","room2",EnrolleePriority.High);
Enrollee e3=new Enrollee("John","room3",EnrolleePriority.Low);
Enrollee e4=new Enrollee("David","room4",EnrolleePriority.Low);
Console.WriteLine("Test start at "+ DateTime.Now.ToString("mm:ss"));
EnrollEnrollee(e1); //e1加入队列后立即执行,isProcessing值赋true
Thread.Sleep(3000);
EnrollEnrollee(e3); //第3秒钟时e3加入队列并等待
Thread.Sleep(1000);
EnrollEnrollee(e2); //第4秒钟时e2加入队列并等待
//第5秒钟时e1完成而e2开好执行,因为在队列中e2的优先级比e3的高
Thread.Sleep(5000);
em.UnEnroll(e3); //第9秒钟时e3等不下了,取消了等待
//第10秒钟时e2完成,队列为空,isProcessing值赋false
Thread.Sleep(6000);
EnrollEnrollee(e4); //第12秒钟时同e1
Thread.Sleep(10000);
Console.WriteLine("Test end at "+ DateTime.Now.ToString("mm:ss"));
}
private static void EnrollEnrollee(Enrollee e)
{
em.Enroll(e);
if(!em.IsProcessing)
em.Run(b);
}
}
以上的注释是我的模拟事件的思路,理论也应该得到那种结果,可是由于运行过程中,EnrolleeQueue.cs中的Remove()方法抛出了异常:
无法将类型为“System.Collections.Generic.Queue`1[Proton.Enrollee]”的对象强制转换为类型“System.Collections.Generic.ICollection`1[Proton.Enrollee]”。
以至e3无被成功删除,使得运行结果和预想的不一致。
这篇Blog本打算昨天就发的,可是在运行过程中发现了这个BUG
我想在不改变数据类型的前提下,直接通过类型转换来修改这了BUG,可是由于我的C#也学得不精通,花了很长时间没有找到解决办法,所以我还是将它发表了,将哪位高手帮我解决这个问题,谢谢!
下载Demo