157

我有一个下拉列表,显示从表到最终用户的值。我想让这些值按字母顺序排序。

根据正确的 MVC 设计,我应该将排序逻辑放在哪一层:模型、视图或控制器?

编辑:在回答 LarsH 的问题时,“您的意思是确定所需排序顺序的代码?还是执行排序的代码?”,我最初指的是确定所需排序顺序的代码。

4

12 回答 12

62

谁控制排序顺序?

简单的MVC图(来自维基百科

1)数据本身的自然顺序:

订单是模型的一部分,所以它应该去那里。“所有数据”的原始拉取将按排序顺序返回数据,并且没有选择排序顺序的界面。

2) 用户应该控制他们如何查看数据:

View 将提供与 Controller 交互的接口(例如升序/降序箭头),并且 Model 对数据的理解足以对数据进行请求的排序。但是,与 (1) 不同,不一定要对数据的原始拉取进行排序。

在任一情况下,

视图不理解正在进行排序,除了显示选择了哪个排序方向的能力。不要把逻辑放在那里。

小警告

在一种情况下(我可以临时想到;可能还有更多),排序功能可以纯粹在视图中进行:

一种“哑”排序,其中所有数据都已经在视图中,并且它不必使用任何领域知识来进行排序。例如,非常简单的字符串或数字比较。例如,当结果可能被拆分到多个页面时,这在网页上的搜索结果中是不可能的。

于 2012-08-15T14:13:00.037 回答
49

(注意:此引用和引文摘自@dasblinkenlight 的回答,但我们不同意我们对它的解释。阅读他的帖子并下定决心)。

根据MVC 描述

控制器可以向其关联视图发送命令以更改视图对模型的表示(例如,通过滚动文档)。它可以向模型发送命令以更新模型的状态(例如编辑文档)。

排序逻辑(例如排序比较器/排序算法)属于模型,因为它包含业务规则和状态数据。由于更改模型数据的排序方式完全属于“更改视图对模型的表示”类别,因此控制器负责通过调用 model.changeSortedState() 方法来“进行排序”。

于 2012-08-15T16:08:31.513 回答
18

根据MVC 描述

控制器可以向其关联视图发送命令以更改视图对模型的表示(例如,通过滚动文档)。它可以向模型发送命令以更新模型的状态(例如编辑文档)。

据此,排序逻辑属于控制器,因为改变模型数据的排序方式直接属于“改变视图对模型的表示”类别。

编辑:为了澄清评论中表达的多种误解,“排序逻辑”不是执行排序的代码;它是定义排序的代码。排序逻辑将各个项目相互比较以建立顺序(例如通过 的实例IComparator<T>)或包含构造要由外部系统用于排序的对象的逻辑(例如通过 的实例IOrderedQueryable<T>)。此逻辑属于您的控制器,因为它需要与应用程序的“业务”端相关的知识。执行排序就足够了,但它与实际执行的代码是分开的它。排序的代码可能在您的视图中,在您的模型中,甚至在支持您的模型的持久层中(例如,您的 SQL 数据库)。

于 2012-08-15T13:19:55.810 回答
10

以上都不是。排序是业务逻辑,业务逻辑不属于这三者中的任何一个。并非应用程序中的每一段代码都是模型、视图或控制器。

我通常在我的 MVC 应用程序中做的是我有一个执行所有业务逻辑的服务层。服务层中的方法应该有一个干净、简单的 API,并带有命名良好的参数。然后,您可以从控制器调用这些方法来操作模型中的数据。

从这个意义上说,排序是“在控制器中”,但是进行排序的代码本身不应该在控制器中实现,只能从那里调用。

于 2012-08-15T18:17:33.477 回答
8

绝对不是控制器:它向视图和模型发送消息,但应该做的工作尽可能少。如果用户可以通过通知模型或视图来更改请求由控制器处理的排序。

如果它是一个纯粹的 View 东西,也许是 View。如果应用程序在没有排序的情况下也能正常工作,那么排序只是表示的一部分,应该出现在视图中。

如果排序是域的固有部分,它应该进入模型。

于 2012-08-15T14:54:56.213 回答
6
  • 视图是 MVC 的一部分,它应该包含表示逻辑。
  • 模型层是包含业务逻辑的地方。
  • 控制器仅根据用户输入更改两者的状态。

所以选择是——你认为这是领域业务逻辑还是表示逻辑的一部分。

如果您正在实现适当的 MVC Model2 或经典 MVC 模式,那么我会说模型层提供的数据的排序应该由视图对模型层的请求触发。视图要求有序数据,模型层提供它。

但是,由于您使用的是 ASP.NET MVC 对 MVC 模式的解释,这与您的标准 MVC 有点不同 - ViewModel 实例应该从模型层请求有序信息(出于某种原因,ASP.NET 框架认为应该调用模板“视图”和视图应该被称为“视图模型”......这很奇怪)。

于 2012-08-15T13:43:04.757 回答
5

我通常会在控制器中执行此操作,以根据其他答案与模式保持一致。推理见下文。

我一直在考虑这个问题并阅读答案和相关材料,务实地说,我会说这取决于您的应用程序,例如:

它是一个中型/大型应用程序和/或有多个与之关联的 UI(即 Windows 应用程序、Web 界面和电话界面)。

  • 在这种情况下,我可能会构建一个服务层并将其放入业务对象中,然后从控制器调用适当的方法。

如果它是一个定义明确的单一 UI 网站,并且您使用的是 EF Code First 之类的东西,并且您没有或无意创建服务层并计划使用简单的开箱即用的扩展方法来实现它:

  • 在这种情况下,我可能会把它放在控制器中,因为它在时间/预算方面最合适。

如果它与上述相同,但无法使用开箱即用的扩展方法实现。

  • 我可能会选择在 Model 类中弹出它(如果它真的是为那个单一类型定制的),因为它在这里比在控制器中更合适。如果排序可以应用于多个类,那么我将在扩展方法中实现它,然后在控制器中调用它。

总结一下:

教条式的回答:服务层

务实的回答:通常是控制器

于 2012-08-15T13:20:29.753 回答
3

我建议从一个足够小以在下拉列表中使用的表数据中排序数据——应该来自已经通过查询排序的数据库。对我来说,这使模型成为应用排序的地方。

如果您决定手动进行排序,我认为使用模型或控制器作为逻辑的首选位置有很好的论据。限制将是您的特定框架。我更喜欢仅在模型中管理数据。我使用控制器来结合数据(模型)和演示(视图),因为我已经(自学)自学了。

于 2012-08-15T19:42:38.243 回答
2

虽然我原则上同意排序是业务逻辑的想法,因为通过将其分解为它的起源,您最终会得到类似“客户希望产品页面显示按日期排序的图像”的结果,那么很明显数据的排序顺序通常不是任意的 - 即使没有排序,因为这仍然是遗漏的业务决策(空列表仍然是列表)。

但是......这些答案似乎没有考虑到ORM技术的进步,我只能谈论与微软的实体框架(让我们避免关于这是否是真正的ORM的争论,这不是重点)作为这就是我使用的,但我确信其他 ORM 也提供类似的功能。

如果我使用 MS MVC 和实体框架为产品类创建强类型视图,并且产品和图像表之间存在外键关系(例如 FK_Product_Image_ProductId),那么我将开箱即用能够快速排序在显示过程中的图像在视图中使用类似这样的东西:

@foreach(Image i in Model.Image.OrderBy(e => e.DisplayOrder)){ //etc etc... }

提到了一个特定的业务逻辑层,我也用它来执行我 80% 的业务逻辑,但我不会将排序功能写入我的业务逻辑层来模仿一些开箱即用的东西来自实体框架。

除了这么说,我认为这个问题没有正确的答案;您应该尽可能抽象复杂的业务逻辑,但不要以重新发明轮子为代价。

于 2012-08-21T22:39:11.703 回答
1

假设您有 MVC 网站、WebForms 网站和一个移动应用程序。

如果您希望这些表示层之间的排序保持一致,那么我会说在表示层之外进行排序。服务将是一个很好的候选人。

否则,我会将该逻辑存储在视图模型中。为什么?因为它将是可重用且易于测试的。

于 2012-08-22T08:05:36.937 回答
0

在您列出的三个中,我会说它属于控制器。不过,我真的不喜欢在控制器中放置这种逻辑。我通常创建一个与控制器通信的服务层,该服务层将负责与数据存储通信并处理排序逻辑。不过,对于小型应用程序,它可以放在控制器中。

于 2012-08-15T13:21:54.327 回答
0

这是一个考虑到 asp.net 的问题,但由于有人确实提到了 Rails,我认为在这种情况下考虑这个问题会很有趣。在 Rails 中,执行排序和检索作为控制器操作是很自然且非常常见的,因为框架和 ActiveRecord/ActiveQuery api 都为此提供了规定。另一方面,可以为静态项目定义某种自定义排序顺序并将其放入模型中以供控制器使用,因此模型可以在排序逻辑中发挥作用,即使它不执行直接操作。不管是什么,可以肯定地说,将排序逻辑放在视图中通常是不受欢迎的。

我有点好笑,有些答案绝对反对将排序放在控制器或模型中,而且我觉得它们对我的口味来说太迂腐了,但我想这取决于所使用框架的性质和与相关的通常约定它。我也同意 Bill K 的评论,即首先进行分离更为重要。

于 2012-08-15T19:47:13.053 回答