我正在尝试使用 MVP 模式,但遇到了设计问题。我正在开发一个具有多个 UserControls 的应用程序。UserControls 本身彼此无关,仅代表实际模型的一个子集。根据我的阅读,人们倾向于说每个视图应该使用一个演示者。这似乎是有道理的,但如果我有 30 个用户控件,我真的想要 30 个演示者吗?另一方面,如果我有 1 个 Presenter 和 1 个 View 代表整个“应用程序”视图,那么我将拥有臃肿的 View 和 Presenter 界面。然后每个视图都必须实现与它无关的方法。我的问题是,有没有更好的方法来处理多个用户控件,或者我应该为每个视图创建 1 个演示者?
4 回答
您应该为每个控件做一个演示者,因为:
- 这将允许您有集中的单元测试只处理该控件
- 由于您不需要支持包含所有控件的呈现逻辑联合的巨大演示者,因此提高了可维护性
- 这将防止在多个页面上具有相同控制的情况下出现冗余
- 通过在页面执行容器特定角色时让控件专注于其特定逻辑来提高 SRP :
通常提到与决策“每个控件的演示者”相关的两个问题:
- 共享上下文是一个问题,由于所有控件只显示同一页面数据上下文的不同部分,这种情况可能看起来像一个有问题的用例,导致每个控件中都有大量数据检索冗余代码。这可以通过依赖注入轻松解决,其中页面(或控制器)执行单个数据检索,然后将数据上下文对象注入每个演示者\视图(通常实现一些启用该功能的接口)。在 MV-VM 模式(Silverlight、WPF)的情况下,可以通过数据边界实现相同的效果,其中页面将设置其 DataContext,然后从视图本身使用
- 同一页面上视图之间的通信是第二个问题,可以使用以下几种方法轻松解决:
- 控件发布页面订阅的事件,然后直接调用其他控件中的适当方法(页面是所有控件的容器,这意味着它知道它们的所有成员)
- 观察者设计模式
- 事件聚合器模式
在这些方法中的每一种中,控件都在相互通信而彼此不知道
将相关的代码分组到一个对象中会更有意义。因此,在这种情况下,如果视图是相关代码的特定分组,那么演示者也会模仿这些分组。为不同的视图设置一个“全局”演示者会将不相关的代码分组到一个对象中。它肯定也会使演示者的界面膨胀。查看单一责任原则。
现在,您可以拥有一个 Presenter Manager 类,也许它可以让您访问每个演示者接口,如接口隔离原则状态,通过任一继承(有一个实现许多演示者接口的全局具体演示者......哪种违反了单一职责) 或聚合(每个接口和 get 函数都有单独的演示者......因此全局接口将是 get 函数)或两者的组合(全局演示者在某种程度上是一个适配器)。
我认为最好的解决方案就是拥有 30 位不同的演示者。
每个 View 不必实现相同的接口... 为什么不为每个控件定义接口,并为包含所有控件的整个屏幕设置一个 Presenter?Presenter 可以根据每个视图需要的接口定义事件“连接”每个视图上的事件,连接到 Presenter 上的适当事件处理程序(如果您正在执行 MVPC,则在控制器上)。您可能还需要另一个接口来表示所有视图都需要共同访问的 Presenter 功能......
- 如果您正在执行 MVPC,则影响模型的视图事件将在控制器中“处理”,而仅影响视图其他部分的视图事件将在演示器上处理。
老问题,但我要直言不讳,不得不不同意其他答案:您不希望每个 UserControl 有一个演示者,就像您希望对每个 UserControl 进行单元测试一样——这将是对 a 的盲目滥用设计模式。
UserControl 不是视图。
应用程序的每个逻辑区域都应该有一个演示者;每一个是如何被分解的——有多少控制,什么显示什么——仅仅是一个组合的问题。