Tom*_*lny 5 .net c# design-patterns
在我的产品中,我需要处理广泛的事件。为此,我使用了这样的代码:
public class Global
{
public static event EventHandler<MyEventArgs> Message;
public static void ShowMessage();
}
Run Code Online (Sandbox Code Playgroud)
现在假设我有一个 WinForms 用户界面。在表单的代码中,我将订阅此事件并以某种默认方式处理它(例如,通过使用 System.Windows.Forms.MessageBox.Show() 方法)。现在的问题是如何允许用户创建派生表单并覆盖我的默认 Message 事件处理程序实现?
仅使用自定义实现第二次订阅事件并不能解决问题(将执行两个事件处理程序并可能显示两个消息框)。我看到的选项是:
//call OnSubscribeToMessageEvent() from either form's constructor or OnLoad event handler
protected virtual void OnSubscribeToMessageEvent()
{
Global.Message += new EventHandler<MyEventArgs>(Global_Message);
}
private void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Run Code Online (Sandbox Code Playgroud)
或者
//subscribe in either form's constructor or OnLoad event handler
protected virtual void Global_Message(object sender, MyEventArgs e)
{
//my default implementation
}
Run Code Online (Sandbox Code Playgroud)
哪个版本更好,为什么?或者也许还有其他选择?
我仍然有一些疑问,因为我从未在任何 .NET 库中见过这样的设计模式
是的,你担心这个是对的。此类事件订阅非常变化无常,事件源总是比订阅者寿命更长。据我所知,框架中只有一个类可以执行此操作,即 SystemEvents。问题在于,每个订阅者在其生命周期结束时都必须非常小心地取消订阅,否则该对象将永远保持引用状态。很难诊断的内存泄漏。
这里更好的模式是使用接口。让我们声明一个:
public class MyEventArgs { /* etc.. */ }
public interface IGlobalNotification {
event EventHandler Disposed;
void OnMessage(MyEventArgs arg);
}
Run Code Online (Sandbox Code Playgroud)
现在您可以让表单实现该接口:
public partial class Form1 : Form, IGlobalNotification {
public Form1() {
InitializeComponent();
GlobalMessages.Register(this);
}
void IGlobalNotification.OnMessage(MyEventArgs arg) {
// do something
}
}
Run Code Online (Sandbox Code Playgroud)
Register 方法向 GlobalMessages 类注册表单,Dispose 事件确保该类可以检测到表单正在死亡:
public static class GlobalMessages {
public static void Register(IGlobalNotification listener) {
listener.Disposed += delegate { listeners.Remove(listener); };
listeners.Add(listener);
}
public static void Notify(MyEventArgs arg) {
foreach (var listener in listeners) listener.OnMessage(arg);
}
private static List<IGlobalNotification> listeners = new List<IGlobalNotification>();
}
Run Code Online (Sandbox Code Playgroud)
调用 GlobalMessages.Notify() 以使 OnMessage() 方法在所有实时表单实例中运行。这种方法的主要优点是客户端程序员永远不会搞砸。
归档时间: |
|
查看次数: |
6441 次 |
最近记录: |