使用 DDay.MVC 管理您的 Model-View-Controller 应用程序






4.11/5 (5投票s)
本文介绍如何使用 DDay.MVC 简化应用程序中的 Model-View-Controller 实现。
为什么选择 Model-View-Controller? 为什么还要费心?
Model-View-Controller 架构已经存在了几十年,并且仍然是开发敏捷且具有前瞻性应用程序的成熟方法。 它有许多好处,包括:
- 分离
- 应用程序逻辑 (Controller)
- 数据 (Model)
- 用户界面 (View)
- 可以交换/替换视图和模型。
- 是否曾经编写过一个您也想为其提供 Web 界面的 Windows 应用程序?
- 是否曾想改变数据的存储方式(例如,文件/数据库/XML)。
- 正确地将职责委派给应用程序的不同区域。
- 您的用户界面不应包含应用程序逻辑。
- 您的模型不应包含应用程序逻辑。
- 您的用户界面不应直接修改数据。
- 等等。
- 促进依赖注入(也称为依赖倒置)。
好处远不止这些。 MVC 还会给您的应用程序带来相当大的复杂性,因此在使用它处理小型应用程序时要小心,因为 MVC 的好处可能不值得您付出这些复杂性。
DDay.MVC
DDay.MVC
是一个库,旨在帮助开发人员利用这些好处,而无需每次手动编写许多特定细节。 DDay.MVC
库负责管理您的 Models、Views 和 Controllers,并将它们连接起来。
下图显示了 DDay.MVC
中使用的应用程序结构:

DDay.MVC
还提供了一些规则强制执行功能,可以防止开发人员违反一些基本的 MVC 规则。 如图所示,模型不应能直接访问视图。 正确设置后,DDay.MVC
会强制执行此规则。
规则
可以从上图得出一些规则:
- GUI 绝不能直接与 Controller 交互。
- GUI 绝不能对 Model 进行更改(例如,保存/删除数据);这必须通过 Controller 进行。
- GUI 只能通过 View “执行操作”。
- GUI 不应自行执行重要的应用程序逻辑 - 这留给 Controller。 它只应执行与通过 GUI 与用户交互直接相关的逻辑。
- GUI 应通过 View 向 Controller “发出请求”。 Controller 可以满足这些请求,或者选择执行它认为合适的任何操作,包括拒绝请求。
- GUI 可以对 Model 执行只读查询,以便显示其正确与用户交互所需的信息。
- GUI 可以通过使用 Model 和 View 公开的事件来检测数据更改。
- View 绝不能对 Model “执行操作”。
- Model 绝不能对 View “执行操作”。
列表还在继续,但我们这里的内容对于我们的目的来说已经足够了。 遵循这些规则很重要,因为它维护了应用程序的整体完整性。 它还确保您可以正确地增强您的应用程序,而不会陷入困境。 这就是 DDay.MVC
发挥作用的地方。
使用代码
从现在开始,我将引用本文示例 MVC 中包含的代码。
本文很难涵盖大部分代码。 至少,大多数人都会在结尾睡着。 所以,为了保持“简洁明了”,我将略过重点,让您自己去探索其余的代码。
另外,当您自己实现时,您需要从 SourceForge.net 获取最新版本的 DDay.MVC
。
项目用途
您可能首先注意到的就是包含的各种项目。 每个项目都有其特定用途,如果理解了这些用途,可能有助于您更好地理解应用程序的整体结构:
- Application.Console - 应用程序的控制台版本
- Application.WinForms - 应用程序的 Windows Forms 版本
- BusinessObjects - 包含业务对象类(例如,
Customer
) - Controller - 包含应用程序的控制器。 这是重要的应用程序逻辑发生的地方。
- Model - 包含应用程序的模型定义。 请注意,这里没有具体的模型。
- Model.DB - 包含一个(假的)数据库模型。 它包含从数据库保存/检索信息的具体模型。
- View - 包含应用程序的视图定义。 一些具体的视图相当通用,可以放在这里(例如,
CustomerView
)。 其他视图特定于 GUI 实现,并放置在其他程序集中(例如,MainView
)。 - View.Console - 包含特定于控制台应用程序的具体视图(例如,
MainView
)。 - View.WinForms - 包含特定于 WinForms 应用程序的具体视图(例如,
MainView
),以及 WinForms 应用程序使用的 GUI 元素(例如,MainForm
、AddNewCustomerForm
等)。
依赖注入
如果您查看 BusinessObjects
项目,您可能会注意到的第一件事是几乎每个类都有一个相应的接口。 如果您熟悉这种做法,您可能已经很好地理解了它的重要性。 如果您不熟悉,我建议阅读 Martin Fowler 的这篇文章,其中演示了依赖注入是多么有益。
您还会注意到在 Model
和 Model.DB
中,接口和相应的具体类被放在了不同的程序集中。 这并非必需,但有助于组织代码和确定程序集依赖关系。 它还有助于保持应用程序的模块化。
MVCManager
您可能很快会注意到的另一件事是 MVCManager
。 MVCManager
是 DDay.MVC
的核心。 它包含您所有的模型和视图,并且可以在您需要时检索它们。
例如,代码使用一个名为 CustomerModel
的模型来存储和检索客户。 如果您想检索客户列表,只需执行以下操作:
// Get the MVCManager for our current process
IMVCManager mvcManager = MVCManager.Current;
ICustomerModelReadonly customerModel =
mvcManager.GetModel<ICustomerModelReadonly>(MVCNames.Customer);
long[] customerIDs = customerModel.GetAllCustomers();
// customerIDs now contains a list of IDs for each customer
List<ICustomer> customers = new List<ICustomer>();
foreach (long id in customerIDs)
customers.Add(customerModel.GetCustomerByID(id));
如前所述,MVCManager
还强制执行 MVC 规则。
事件连接
如果您查看 CustomerController
,您会注意到用于连接和断开事件的方法。 这些方法会在 Views/Models 更改时自动调用,并确保 Controller 与 Views/Models 之间的通信线路设置正确。
在 WireupXXX()
方法中,您需要订阅 Model 或 View 触发的任何您感兴趣要处理的事件。 来自 View 对 Controller 的任何请求都应以这种方式处理。 相反,您需要在 TeardownXXX()
方法中取消订阅事件。 这可以防止出现被错误触发的事件处理程序(这在过去曾给我带来很多麻烦)。
反馈
如果您想发布 bug/功能请求,请使用 Sourceforge 项目页面。 我很感激任何人愿意提供的帮助。
附加说明
本文写于 2009 年 2 月,基于 DDay.MVC
的 0.84 版本。 自那时以来,情况可能已发生重大变化,因此请务必查看 Sourceforge 项目以获取更新,因为您遇到的任何 bug 可能已经在最新版本中得到修复。