我有一个下拉列表,它向最终用户显示表中的值。我希望按字母顺序对这些值进行排序。
根据正确的 MVC 设计,我应该把我的排序逻辑放在哪一层: 模型、视图还是控制器?
编辑 : 对于 LarsH 的问题,“您是指确定需要什么排序顺序的代码吗?还是执行排序的代码?”,我最初指的是确定需要什么排序顺序的代码。
根据 车祸描述,
控制器可以向其关联的视图发送命令,以更改模型的视图表示形式(例如,通过滚动文档)。它可以向模型发送命令来更新模型的状态(例如编辑文档)。
根据这一点,排序逻辑属于控制器,因为改变模型数据的排序方式直接属于“更改模型的视图表示”的范畴。
编辑: 为了澄清注释中表达的多个误解,“排序逻辑”是执行排序的代码 没有; 它是执行排序的代码 定义。排序逻辑将各个项目相互比较以建立一个顺序(例如通过 IComparator<T>的一个实例) ,或者包含构造一个对象以供外部系统(例如通过 IOrderedQueryable<T>的一个实例)进行排序的逻辑。这种逻辑属于您的控制器,因为它需要与应用程序的“业务”方相关的知识。执行排序是完全足够的,但是它与实际的 表演代码是分开的。排序的代码可能在您的视图、模型中,甚至在支持模型的持久层(例如 SQL 数据库)中。
IComparator<T>
IOrderedQueryable<T>
我通常会在控制器中按照其他答案的模式进行操作。请看下面的推理。
我一直在仔细考虑这个问题,阅读答案和相关材料,从实用的角度来说,这取决于你的申请,例如:
它是一个中型/大型应用程序和/或有多个用户界面相关联(例如,一个 Windows 应用程序,Web 界面和电话界面)。
如果它是一个定义良好的单一 UI 网站,你正在使用类似 EF Code First 的东西,而且你没有或者根本没有打算创建一个服务层,并计划使用一个简单的开箱即用的扩展方法来实现它:
如果与上面的相同,则不能使用开箱即用的扩展方法实现。
总而言之:
武断的回答: 服务层
务实的回答: 通常是控制器
在您列出的三个中,我认为它属于控制器。不过,我真的不喜欢把这种逻辑放在控制器中。我通常创建一个服务层,控制器与之通信,该服务层负责与数据存储区通信和处理排序逻辑。不过,对于小型应用程序,它可以放在控制器中。
所以选择是——您认为这是领域业务逻辑或表示逻辑的一部分吗。
如果您正在实现一个合适的 MVC Model2或经典的 MVC 模式,那么我会说,模型层提供的数据的排序应该由视图对模型层的请求触发。视图需要有序的数据,模型层提供这些数据。
但是,由于你使用的是 ASP.NET MVC 对 MVC 模式的解释,这与你的标准 MVC 有点不同—— ViewModel 实例应该从模型层请求有序信息(出于某种原因,ASP.NET 框架认为模板应该被称为“视图”,而视图应该被称为“视图模型”。.很奇怪)。
(来自 维基百科)
订单是模型的一部分,所以应该放在那里。“所有数据”的原始提取将按排序顺序返回数据,并且没有选择排序顺序的接口。
视图将提供一个与控制器交互的接口(如升序/降序箭头) ,模型对数据的理解足以对数据进行请求的排序。然而,与(1)中不同的是,数据的原始拉取并不一定需要排序。
视图不理解有一个排序正在进行,其他能力显示哪个排序方向已经选择。不要把逻辑放在那里。
排序功能 可以纯粹在视图中,在一种情况下(我可以随便想到; 可能还有更多) :
一种“哑”排序,其中所有数据都已经在视图中,并且不需要使用任何领域知识进行排序。例如,非常简单的字符串或数字比较。这是不可能的,例如,在一个网页上的搜索结果时,结果可能被分割成多个页面。
当然不是控制器: 它向视图和模型发送消息,但应该尽可能少地进行工作。如果用户可以通过通知模型或视图来更改请求由控制器处理的排序。
如果它是一个纯粹的视图的东西,也许观点。如果应用程序在不排序的情况下也能正常工作,那么排序只是表示的一部分,应该放在视图中。
如果排序是域固有的一部分,那么它应该进入模型。
(注: 此引文和引文摘自 @ dasblinkenlight 的回答,但我们对其解释不一致。阅读他的文章,然后自己做决定)。
排序逻辑(例如,排序比较器/排序算法)属于模型,因为它包含业务规则和状态数据。由于改变模型数据的排序方式直接属于“更改模型的视图表示”类别,因此控制器负责通过调用 model. changeSortedState ()方法“进行排序”。
都不是。排序是业务逻辑,业务逻辑不属于这三种逻辑中的任何一种。并非应用程序中的每段代码都是模型、视图或控制器。
我通常在我的 MVC 应用程序是我有一个服务层,执行所有的业务逻辑。服务层中的方法应该具有一个干净、简单的 API,并具有命名良好的参数。然后可以从控制器调用这些方法来操作模型中的数据。
从这个意义上说,排序是“在控制器中”,但是执行排序的代码本身不应该在控制器中实现,只能从控制器中调用。
我建议对表中的数据进行排序——这些数据足够小,可以在下拉列表中使用——应该来自已经通过查询进行排序的数据库。对我来说,这使得模型成为应用排序的地方。
如果您决定手工进行排序,我认为使用模型或控制器作为逻辑的首选位置有很好的理由。限制将是您的特定框架。我倾向于在模型中单独管理数据。我使用控制器将数据(模型)和表示(视图)结合起来,就像我自学的那样。
考虑到 asp.net,这是一个问题,但是因为有人提到了 Rails,我认为在这种情况下考虑这个问题会很有趣。在 Rails 中,将排序和检索作为控制器操作一起执行是非常自然和常见的,因为框架和 ActiveRecord/ActiveQuery api 为它提供了支持。另一方面,可以为静态条目定义某种自定义排序顺序,并将其放入控制器所使用的模型中,因此模型即使不直接执行操作,也可以在排序逻辑中发挥作用。不管是什么,可以肯定地说,将排序逻辑置于视图中通常是不受欢迎的。
我有点好笑的是,有些答案是绝对反对在控制器或模型中进行排序的,我发现它们对我来说太迂腐了,但我认为这取决于所使用框架的性质以及与之相关的常规约定。我也同意比尔 · K 的观点,即分居更为重要。
虽然我原则上同意排序是业务逻辑的想法,因为通过把它分解成它的起源,你最终会得到类似“客户希望产品页面显示按日期排序的图像”这样的东西,那么很明显,数据的排序顺序通常不是任意的——即使没有排序,因为这仍然是一个由遗漏(一个空列表仍然是一个列表)的业务决策。
但是... ... 这些答案似乎没有考虑到 ORM 技术的进步,我只能谈论实体框架(让我们避免争论这是否是真正的 ORM,这不是重点) ,因为这是我使用的,但我相信其他 ORM 提供类似的功能。
如果我使用 MS MVC 和实体框架为 Product 类创建了一个 Strong Type 视图,并且在 Product 和 Image 表之间有一个外键关系(例如 FK _ Product _ Image _ ProductId) ,那么我就可以在图像显示过程中使用类似视图中的东西快速排序图像:
@foreach(Image i in Model.Image.OrderBy(e => e.DisplayOrder)){ //etc etc... }
这里提到了一个特定的业务逻辑层,我也使用它来执行80% 的业务逻辑,但是我不打算在我的业务逻辑层中编写模仿实体框架的排序功能。
我不认为这个问题有一个正确的答案,除了说,你应该抽象复杂的业务逻辑在可能的地方,但不是以重造轮子为代价。
假设您有 MVC 网站,WebForms 网站和一个移动应用程序。
如果您希望在这些表示层之间保持排序的一致性,那么我建议在表示层之外进行排序。服务是个不错的选择。
否则,我会将这个逻辑存储在一个视图模型中。为什么呢? 因为它将是可重用的和易于测试的。