Keywords: Event, delegate, Publish and subscribe pattern
我打算设计一个程序, 它能一次性美化一个目录之下所有的xml文件, 在UI上, 要求能显示处理的进度(即每处理完一个xml文件, UI的ProgressBar就变化一下). 美化xml的由SourcePackage类的BeautifyFiles方法完成, 而UI是另一个类FormMain. 显然这要处理SourcePackage类和FormMain类之间的通讯问题. 怎样解决这个问题呢? 这其实这是一个如何解耦的问题.
如果你学过C语言, 你会很自然想到使用回调函数, 即在FormMain类中新增一个方法, 比如UpdateProgressBar(), 然后将UpdateProgressBar()这个函数传给SourcePackage.BeautifyFiles()方法. 这确实是一个解决方法. 即将一个被调用者传给调用者. 这种方法直接有效, 但耦合度很高.
另一个方案是, 采用Publish-Subscribe模式, 使用这个模式, 首先要定义一个通知, 即发布什么, 以及订阅什么. 就本实例来讲, 这个通知就是一个xml文件已经被处理完了, 在UI类中, 订阅这个通知, 然后再编写这个通知的一个Handler函数(即进行更新进度条).
C#就是采用Publish-Subscribe来实现Event, 因为C#Delegate支持多播, 所以非常完美地实现了Publish-subscribe; 如果你使用C++, 也可采用了Observer模式来实现Event. 我们用C#的Event来实现设计要求. 设计的详细思路是:
在Publish方(Publish方多数为一个服务的服务端), 需要完成的工作是:
(1) 如果需要的话,使用delegate来定义通知类型, (一般的EventHandler已经在Framework中定义了, 特殊的Handler需要自定义)
public delegate void OneXmlProcessedEventHandler(object sender, ProcessCountEventArgs e);
(2) 在SourcePackage类中, 使用event关键字来发布通知.
public event OneXmlProcessedEventHandler OneXmlProcessed;
(3) 在SourcePackage.BeautifyFiles()触发这个通知的Handler.
foreach (Stream fileStream in m_ListFileStream)
{
m_FileBeautifier.FileStream = fileStream;
m_FileBeautifier.Beautify();
if (OneXmlProcessed != null)
{
eventArgs.ProcessedIndex = eventArgs.ProcessedIndex+1 ;
OneXmlProcessed(this, eventArgs);
}
}
在Subscribe方(Subscribe方多为服务的消费端), 需要完成的工作是:
(1) 订阅这个通知
SourcePackage sourcePackage = new SourcePackage(packageFullName);
sourcePackage.OneXmlProcessed += new OneXmlProcessedEventHandler(OneXmlProcessedHandler);
(2) 编写通知Handler
void OneXmlProcessedHandler(object sender, ProcessCountEventArgs e)
{
const string progressIndicator="{0} of {1} is proceeded!" ;
toolStripStatusLabel1.Text = string.Format(progressIndicator, e.ProcessedIndex, e.FileCount);
toolStripProgressBar1.Value = e.ProcessedIndex;
Application.DoEvents();
}
No comments:
Post a Comment