【发布时间】:2008-12-01 02:49:12
【问题描述】:
模型应该只是数据结构吗?服务(数据访问、业务逻辑)在 MVC 中位于何处?
假设我有一个显示客户订单列表的视图。我有一个控制器类来处理视图控件(按钮等)上的点击。
控制器是否应该启动数据访问代码?想按钮点击,重新加载订单查询。还是应该通过模型层?
任何示例代码都会很棒!
【问题讨论】:
-
@ak,我尝试编辑它以改进问题,包括添加更好的标题。请随时改进我的编辑:-)
模型应该只是数据结构吗?服务(数据访问、业务逻辑)在 MVC 中位于何处?
假设我有一个显示客户订单列表的视图。我有一个控制器类来处理视图控件(按钮等)上的点击。
控制器是否应该启动数据访问代码?想按钮点击,重新加载订单查询。还是应该通过模型层?
任何示例代码都会很棒!
【问题讨论】:
一般我实现MVC如下:
View - 从控制器接收数据并生成输出。通常这里应该只出现显示逻辑。例如,如果您想利用现有网站并制作它的移动/iPhone 版本,您应该能够通过替换视图来做到这一点(假设您想要相同的功能)。
Model - 在模型中包装对数据的访问。在我的应用程序中,所有 SQL 都位于模型层中,视图或控制器中不允许直接访问数据。正如 Elie 在另一个答案中指出的那样,这里的想法是(至少部分地)将您的控制器/视图与数据库结构的变化隔离开来。模型也是实现逻辑的好地方,例如每当字段更改时更新“最后修改”日期。如果您的应用程序的主要数据源是外部 Web 服务,请考虑是否将其包装在模型类中。
控制器 - 用于将模型和视图粘合在一起。在此处实现应用程序逻辑、验证表单、将数据从模型传输到视图等。
例如,在我的应用程序中,当请求页面时,控制器将从模型中获取所需的任何数据,并将其传递给视图以生成用户看到的页面。如果该页面是表单,则可以提交表单,控制器处理验证,创建必要的模型并使用它来保存数据。
如果您遵循这种方法,模型最终会变得非常通用且可重用。您的控制器具有可管理的大小和复杂性,因为数据访问和显示已分别移至模型和视图,并且您的视图应该足够简单,以便设计人员(经过一些培训)能够理解它们。
【讨论】:
我不会将数据访问代码放入控制器中。
要建立在已经说过的基础上,重要的是要考虑在层内分层。例如,您可能在模型本身中有多个层——一个执行任何 ORM 和数据库访问的数据访问层和一个代表业务对象的更抽象的层(不知道如何访问它们的数据)。
这将使您能够更轻松地测试系统的组件,因为它支持模拟。
【讨论】:
我喜欢在域(模型)层中保留用于模型持久性或服务访问的“合同”或接口。我将数据访问或服务调用的实现放在另一层。
控制器通过构造函数进行实例化,构造函数采用服务接口,例如ISomeService,作为参数。控制器本身不知道服务层是如何实现的,但他们可以访问它们。然后我可以轻松替换 SqlSomeService 或 InMemorySomeService。
我也非常满意具体的服务实现,它将域(模型)层存储库作为其构造函数的参数。例如:ICatalogRepository 和 SqlServerCatalogRepositry:ICatalogRepository 被交给 CatalogService(ICatalogRepository, ISomeOtherDependency)。
依赖注入框架更容易实现这种分离。
【讨论】:
View 会将在 UI 中单击时应该发生的事情传递给 Control 层,该层将包含所有业务逻辑,然后会调用 Model 层,该层只会进行数据库调用。只有模型层应该进行数据库调用,否则您将违背 MVC 设计模式的目的。
这样想。假设您更改了数据库。您可能希望限制所需的代码更改量,并将所有这些更改放在一起,而不影响应用程序的其他部分。因此,通过将所有数据访问保留在模型层中,即使是简单的调用,您也可以限制模型层所需的任何更改。如果您出于任何原因绕过模型层,您现在必须将所需的任何更改扩展到任何了解数据库的代码,这使得此类维护比应有的复杂。
【讨论】: