烧水器事件簿 的简单实现

昨天看了Allen Lee写的一篇好文《烧水器事件簿 [Design, C#] 》

不过由于本人学艺不精,看了好久才把握了它的工作流程。于是将他的代码作了小小改动并编写了一段测试代码对它进行了一个简单的实现:

1.在EnrollManager.cs中的Run()方法中增加了对Enrollee的Boil()方法的调用,让整个流程动作起来,同理也对MoveNext()作了改动,并加了两个WriteLine()显示,添加了IsProcessing属性反映是否有有人在使用Boiler,如果为真,则加信队列的人可直接由MoveNext()驱动,否则就要调用EnrollManager的Run()方法来驱动。

ContractedBlock.gif ExpandedBlockStart.gif
None.gif        private void MoveNext(object sender, EnrolleeEventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
if (m_Queue.Count == 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            m_Enrollee.Watered 
-= new EnrolleeEventHandler(MoveNext);
InBlock.gif            Run(e.Boiler);
ExpandedBlockEnd.gif        }

None.gif
None.gif        
public void Run(Boiler boiler)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            m_Enrollee 
= m_Queue.Dequeue();
InBlock.gif            m_Enrollee.Boiler 
= boiler;
InBlock.gif            m_Enrollee.Boil();
ExpandedBlockEnd.gif        }

2.Enrollee.cs中将倒水时间设为1秒,然后加入了对Done()方法的调用。就是假设Enrolee完成倒水后就马上告诉EnrollManager,Boiler我用完了,你去分配它吧,即实现作者所说了Enrollee对Done()的手动调用。

3.Boiler.cs中增加了UserName属性,我觉得这很有必要,因为那些等待的人知道,现在谁在使用Boil。然后将烧水的时间提高到了4秒,呵呵,为了快点看到测试结果。

4.最后就是编写了事件模拟Program.cs:

None.gif using  System;
None.gif
using  System.Collections.Generic;
None.gif
using  System.Text;
None.gif
using  System.Threading;
None.gif
using  Proton;
None.gif
None.gif
class  Test
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
private static EnrolleeManager em=new EnrolleeManager();
InBlock.gif    
private static Boiler b=new Boiler();
InBlock.gif    
public static void Main()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        Enrollee e1
=new Enrollee("Paul","room1",EnrolleePriority.High);
InBlock.gif        Enrollee e2
=new Enrollee("Henry","room2",EnrolleePriority.High);
InBlock.gif        Enrollee e3
=new Enrollee("John","room3",EnrolleePriority.Low);
InBlock.gif        Enrollee e4
=new Enrollee("David","room4",EnrolleePriority.Low);
InBlock.gif
InBlock.gif        Console.WriteLine(
"Test start at "+ DateTime.Now.ToString("mm:ss"));
InBlock.gif
InBlock.gif        EnrollEnrollee(e1); 
//e1加入队列后立即执行,isProcessing值赋true
InBlock.gif

InBlock.gif        Thread.Sleep(
3000);
InBlock.gif        EnrollEnrollee(e3); 
//第3秒钟时e3加入队列并等待
InBlock.gif
        
InBlock.gif        Thread.Sleep(
1000);
InBlock.gif        EnrollEnrollee(e2); 
//第4秒钟时e2加入队列并等待
InBlock.gif                            
//第5秒钟时e1完成而e2开好执行,因为在队列中e2的优先级比e3的高
InBlock.gif
        Thread.Sleep(5000);
InBlock.gif        em.UnEnroll(e3);    
//第9秒钟时e3等不下了,取消了等待
InBlock.gif                            
//第10秒钟时e2完成,队列为空,isProcessing值赋false
InBlock.gif
        Thread.Sleep(6000);   
InBlock.gif        EnrollEnrollee(e4); 
//第12秒钟时同e1 
InBlock.gif
       
InBlock.gif        Thread.Sleep(
10000);
InBlock.gif
InBlock.gif        Console.WriteLine(
"Test end at "+ DateTime.Now.ToString("mm:ss"));
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
private static void EnrollEnrollee(Enrollee e)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        em.Enroll(e);
InBlock.gif        
if(!em.IsProcessing)
InBlock.gif            em.Run(b);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


以上的注释是我的模拟事件的思路,理论也应该得到那种结果,可是由于运行过程中,EnrolleeQueue.cs中的Remove()方法抛出了异常:
无法将类型为“System.Collections.Generic.Queue`1[Proton.Enrollee]”的对象强制转换为类型“System.Collections.Generic.ICollection`1[Proton.Enrollee]”。
以至e3无被成功删除,使得运行结果和预想的不一致。

这篇Blog本打算昨天就发的,可是在运行过程中发现了这个BUG
我想在不改变数据类型的前提下,直接通过类型转换来修改这了BUG,可是由于我的C#也学得不精通,花了很长时间没有找到解决办法,所以我还是将它发表了,将哪位高手帮我解决这个问题,谢谢!
 
下载Demo

转载于:https://www.cnblogs.com/nihgwu/archive/2006/08/05/468219.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值