【问题标题】:problems designing event driven communication设计事件驱动通信的问题
【发布时间】:2009-12-18 22:13:18
【问题描述】:

我在设计问题上有点挣扎。我在 C# 中制作了一个非常简单的 gui 系统。该代码旨在可重用,因此我在这里寻找最灵活的解决方案。我提出的解决方案似乎都有其缺点。

为简单起见,我们假设存在三个类:控制器、按钮和客户端代码。客户端代码是使用 gui 系统的代码。它创建控制器并在其上调用 Update()。控制器创建一堆按钮实例并在它们上调用 Update()。按钮会自行绘制并检查鼠标点击。

现在的问题是我如何才能知道按钮被点击到客户端代码的事实?

选项 1:将 GetButton(string name) 添加到控制器类。然后客户端代码可以订阅按钮 class=> GetButton("but").MouseUpEvent += MouseUpHandler; 中定义的事件。这样做的缺点是,这会暴露 Button.Update(),并且只能由控制器使用。

选项 2:让控制器订阅所有按钮,客户端代码订阅控制器。这里的缺点是在客户端代码中解析代码更多,因为现在所有事件都通过控制器汇集,因此客户端必须检查哪个按钮发送了每个事件。我更喜欢像选项 1 那样在初始化阶段设置事件流。

选项 3:为每个事件向控制器添加订阅/取消订阅方法(SubscribeMouseUp(string buttonName, GUIDelegate del) 等)缺点是控制器 api 增长很快。

所以现在我倾向于选项 1,但 GetButton 返回一个仅声明事件的接口(可能是 IClientButton),从而对客户端隐藏了 Update(),但我不确定这是否是应该使用接口的方式.

感谢任何见解。 巴斯

【问题讨论】:

    标签: c# events event-handling


    【解决方案1】:

    大概这是一个问题,因为Update() 是公开的?

    假设您已将按钮和控制器组织到同一个命名空间中,使用internal 保护是否适合您的需求?

    【讨论】:

      【解决方案2】:

      接口可以这样使用,INotifyPropertyChanged 是一个与 1 个项目的接口,它是一个事件。

      使用RoutedEvents怎么样?

      【讨论】:

        【解决方案3】:

        还有第四个,也许是更受欢迎的选择。

        将调度程序作为注册/注销的中心位置。所有事件接收器都向调度程序注册一个回调。所有事件生成器都将它们的事件发送给调度器。

        它使 API 更简洁,并有助于解开对象引用。

        【讨论】:

          【解决方案4】:

          在您的控制器中,添加两个事件 - ButtonCreatedButtonDestroyed

          public event EventHandler<ClientButtonEventArgs> ButtonCreated;
          public event EventHandler<ClientButtonEventArgs> ButtonDestroyed;
          

          ClientButtonEventArgs 只是您的IClientButton 接口的EventArgs 包装器。

          让您的客户端代码订阅这两个事件。当控制器创建一个新按钮时,让它触发ButtonCreated 事件。然后,客户端代码可以在收到事件通知时订阅必要的 Button 事件。同样,Controller 将在必要时触发 ButtonDestroyed 事件,允许客户端代码取消订阅 Button 的事件。

          这样,整个序列是事件驱动的。客户端代码对按钮的创建和销毁做出反应,这似乎就是您所追求的。

          【讨论】: