`
mmdev
  • 浏览: 12946566 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

[连载] 用C#进行思考(三 之 前传)用委托实现回调

阅读更多

  前文提到过回调。也就是当发生不得不由生产者调用消费者时,不能直接使用方法调用,必须使用回调。

(插:虽然在这里我对回调提出了新的定义,但实际上与传统意义上的回调并不冲突。试想一下Windows中的回调,基本上都是系统为我们提供了一写功能[生产者],而我们在调用这些功能时,又必须为其提供一个操作,以便其进行调用,这时才会产生回调。)

  在.NET中,使用委托实现回调。委托有两种方式——将委托作为参数传递、将委托作为类的域(Field)成员。前者就是这里要说的,很简单;而后者,放在下一篇文章再说,作为域成员的委托直接导致了事件的诞生。

  考虑在老板(消费者)和员工(生产者)之间,老板希望在员工做完工作后进行检查。

//Boss.cs
publicclassBoss
...{
Employeem_anEmployee
=newEmployee();

publicviodDispatchJob()
...{
try//异常处理在大多数情况下是需要的,因为工作不一定成功
...{
m_anEmployee.DoJob();
m_check();
//检查工作
//将“工作状态”改为“完成”
}

catch(Exceptionex)
...{
//处理异常情况
//将“工作状态”改为“错误”
}

}


privatevoidm_check()
...{
//执行对工作的检查
}

}


//Employee.cs
publicclassEmployee
...{
publicvoidDoJob()
...{
//完成工作,出错时抛异常
}

}

  在这里,作为消费者的老板,做了太多的事情(无论出于实际生活,还是出于在编程中的体验,都是不合理的)。因此这里也暴露出一种经验,就是当你发现你的一个类型,作为生产者的角色时,其实现太过简单,那么说明你的设计一定是有问题的。

  考虑这样一个问题,如果在使用Employee时,忘记作异常处理怎么办?忘记了调用check,没有检查工作怎么办?又或者不忘,那么每写一个用到了员工的类型或方法时,都要添加这样的代码,重复工作也是不能忍的。尤其是当DoJob方法要消耗大量时间时,每个调用都要在Boss中单独开启后台线程,工作量繁重且易出错。注意在这种方式下不能在DoJob中开启后台线程,否则就不能保证m_check方法是在DoJob完成后调用的。

  考虑使用回调。

//Boss.cs
publicclassBoss
...{
Employeem_anEmployee
=newEmployee();

publicviodDispatchJob()
...{
JobFinishedCallbackcb
=newJobFinishedCallback(m_check);
m_anEmployee.DoJob(cb);
//使用回调,简化了调用
}


privatevoidm_check(JobStates)
...{
if(s=JobState.Finished)
//进行具体的检查
else
//处理错误
}

}


//Employee.cs
publicdelegatevoidJobFinishedCallback(JobStates);

publicenumJobState
...{
Finised,Error
}


publicclassEmployee
...{
publicvoidDoJob(JobFinishedCallbackcb)
...{
try//可以在DoJob内部处理错误
...{
//完成工作,出错时抛异常
if(cb!=null)
cb(JobState.Finished);
}

catch(Exception)
...{
if(cb!=null)
cb(JobState.Error);
}

}

}

  现在,Boss的实现变得非常简单。如果需要添加后台线程,也只需在Employee中添加即可。甚至,还可以将多个方法链接到cb回调中(别忘了C#使用多播委托),用一系列方法来处理JobFinished这件事。(咦,事件的概念是不是冒出来了?且听下回分解。)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics