设计:如何通知控制器有关跨应用程序的数据修改

Posted

技术标签:

【中文标题】设计:如何通知控制器有关跨应用程序的数据修改【英文标题】:Design: How to inform controllers about data modification across application 【发布时间】:2012-06-18 14:24:56 【问题描述】:

在基于 mvc 的大型系统中,有负责编辑数据的视图和显示该数据的视图。

示例:UserManagementViewUserSelectionView

每个子系统都应该知道它是否需要数据更新,在另一个子系统对相同数据进行更改之后,以便其控制器知道是否需要数据更新。

我对此的想法类似于观察者模式(有点集成在 c# 中),所有控制器都将是侦听器,最终会收到发生数据操作的通知。

BindingList<> 例如提供了一个ListChanged 事件。类似地,可以为每个数据结构创建一个接口,并将更改通知控制器。这会增加开销 (IMO),而且我发现这个解决方案很难在大型系统中维护,而且无论如何更新数据也不是解决方案。

哪种架构设计可以在这种情况下提供帮助?

【问题讨论】:

控制器应该决定这个吗?为什么它不将此任务委托给业务类? 是的。其实我对这种设计的架构更感兴趣。您是正确的,控制器负责。问题仍然存在.. 【参考方案1】:

我已经成功使用Publish–subscribe pattern 模式解决了这类问题。每当有人修改某些人可能有兴趣知道的内容时,您就会引发“ObjectWasModified”事件,或者如果您想要更具体的事件,例如“NewUserAdded”等……然后,每个子系统或其他需要知道的事情何时发生发生时,它订阅该类型的事件。您可以在 Event ObjectWasModified 或附加条件中添加模板参数,因此每个系统只接收它真正感兴趣的事件。

【讨论】:

【参考方案2】:

我知道 WPF 与 MVVM 的结合在很大程度上依赖于 INotifyPropertyChanged 和额外的 INotifyCollectionChanged。也许这个简单的界面可能会为您解决问题。

阅读here。 Josh Smith 的一篇关于 MVVM 基础的文章,您可以通过该文章了解INotifyPropertyChanged 的使用。虽然它是在 WPF 环境中,但它也可以在 WinForms 中使用。

【讨论】:

【参考方案3】:

为什么不直接使用 .NET 中内置的事件模型?我没有正确理解这个问题吗?您的问题表明您认为这会增加很多“开销”(不清楚您是指性能还是开发),但从性能的角度来看,此解决方案非常轻量级。

class YourModel

    //---- event class can contain data elements to update listeners
    public class DataChangedEventArgs : EventArgs
    
        ...
    

    //---- this is what the client callback need to look like
    public delegate void DataChangedDelegate(object oSender, DataChangedEventArgs args);

    //---- public event that clients subscribe to
    public event DataChangedDelegate evtDataChanged;

    //---- any changes in YourModel invoke this method to notify clients
    protected void OnChanged(DataChangedEventArgs args)
    
        if (evtDataChanged != null)
            evtDataChanged(this, args);
    

    //---- method(s) in your Model that change internal data
    public void ImaDataChanger(...) 
    
        //---- stuff that changes the data

        OnChanged(args);    //-- notify clients
    


class UserSelectionView

    //---- the event callback
    public void DataChangedHandler(object oSender, YourModel.DataChangedEventArgs args)
    
        //---- process update or refresh data
        //---- UI updates will have to be marshalled to the UI thread
    

    //---- sign up for events
    public void Subscribe(YourModel model)
    
        model.evtDataChanged += new YourModel.DataChangedDelegate(DataChangedHandler);
    

您可以选择定义其他事件或将数据成员添加到 DataChangedEventArgs 以提供有关数据更改类型的信息。

另外,如下面的 cmets 所示,如果您需要将视图放在不同的计算机上或同一台计算机上的不同进程中,您可以使用 .NET Remoting 来实现这一点,只需很少的代码更改。

【讨论】:

这是一个有趣的问题,因为它是一个带有特定用例的抽象问题。 .Net 事件模型不适用于基于 Web 的 MVC 应用程序,因为视图在呈现之前的生命周期很短。除非您有一些 pub-sub 系统设置来执行此操作,否则您不能强制从 .Net 事件刷新网页。但是,您的建议可能适用于单台计算机上的 winforms 应用程序(这是 OP 所要求的,我只是在学术上思考:-)。 它特别说明了WinForms。我不会为 ASP 推荐这个解决方案。此外,您关于这仅适用于单台计算机的断言是错误的。使用 .NET Remoting,这个解决方案可以很容易地扩展到单台计算机上的多个进程或运行在不同计算机上的视图客户端。只是为了通知学术辩论......【参考方案4】:

这个问题听起来像是您试图在没有模型部分的情况下使用 MVC。如果我误解了,编辑您的问题以包含一个实际用例(示例)可能有助于我们理解上下文。

不过,一般来说,您的控制器中不应真正持久/存储任何内容。所以控制器中应该没有任何东西需要“更新”或“通知”(即:没有数据)。相反,数据应该位于管理所有数据的单独“模型”层中。然后视图从模型层读取以获取该视图的任何数据。

如需快速复习,请查看wikipedia page on MVC,它有一个不错的经典 MVC 流程图和关于组件交互的简单文章。

讨论示例

让我们试着设计一个例子来理解这个问题。

假设我的应用程序中有一个用户列表。此列表可能显示在:

主管理员列表视图 管理员编辑用户视图 用户的个人资料视图 也许更多?

每个视图都会从模型层请求数据并在屏幕上显示一些内容。

现在假设对一位用户的个人资料进行了更改。这将通过一个控制器方法来完成,该方法执行任何必要的工作以将某些更改应用于模型。

我的理解是,您希望所有这些视图都更新以反映这种变化。这意味着视图需要从模型中重新加载数据。它不应该从控制器本身获取此数据,即使控制器触发此重新加载/刷新 - 或者更确切地说,控制器方法可能有助于从模型层进行查询。重要的是,您不会在整个应用程序的多个控制器中维护数据的多个副本。持久化集中在模型层。

在 winforms 的情况下,如果您的 UI 组件被构建为识别该接口并相应地刷新,模型层可能能够提供类似于提到的 INotifyPropertyChanged 接口的东西。但这是一种相当依赖于平台的方法。

一种更与平台/上下文无关的方法是已经提到的发布-订阅(发布-订阅)模式。在这种情况下,对模型进行更改的每个控制器方法也会发布其更改的通知。该数据的任何视图都可以通过从模型层刷新/重新加载视图数据来监听并响应此类通知。

【讨论】:

以上是关于设计:如何通知控制器有关跨应用程序的数据修改的主要内容,如果未能解决你的问题,请参考以下文章

如何将模块中的格式化子例程应用于跨工作簿的各种范围

通知 GUI 对象有关屏幕大小的信息 - 设计

从已关闭的应用程序发送有关新 JSON 数据的本地通知? |迅速

如何通知您的 android 应用程序有关推送通知

应用程序设计:处理带有背景上下文的核心数据;合并由 MOC 过滤的通知

如何实现推送通知跨浏览器?