我应该在不同的视图中重用视图模型吗?

时间:2012-08-30 21:19:26

标签: c# asp.net-mvc viewmodel

我注意到我的观点需要与其他人一样的信息。但有时您需要视图模型的5个属性,有时只需要2.

您是否在多个视图中共享此类视图模型,或者您是否为每个视图创建了单独的视图模型,或者您是否优先选择继承组合策略?

对我来说,共享视图模型有一些缺点:

  1. 最小惊喜原则:只填充视图模型中的5个属性并获取空引用异常是很奇怪的,因为您不想查询数据库的其他数据。当视图模型有5个属性时,我希望所有属性都被填充。例外证明了规则。
  2. 关注点分离/单一责任原则:视图模型在复杂网站上混乱,因为您必须满足每个视图的不同需求。如果涉及逻辑,它也会变得更加复杂。
  3. 你怎么看?你是如何处理这种情况的?

7 个答案:

答案 0 :(得分:9)

人们倾向于根据他们使用的观点对ViewModel有不同的理念。 ViewModels是视图和模型之间的粘合剂,人们通常会根据他们喜欢的两端更加严格来确定答案。

  • 如果您希望模型/数据对象更加严格,那么您将倾向于将ViewModel与模型/数据联系起来,即。您将拥有一个在多个视图中使用的ViewModel,并让ViewModel根据您希望如何处理数据加载(以及延迟图像或其他长期负载属性等)来确定要检索的属性。
  • 如果您希望您的视图更加严格,那么您将ViewModel更接近View - 即。每个视图都有一个单独的ViewModel,当你从视图移动到视图时,让模型/数据对象处理同步等事情。

就个人而言,我更喜欢第一种,因为我的数据往往更加严格,因为它比视图更不可能改变(在我的项目中 - 我不认为这是数据的通用属性和意见)。由于更改通知是ViewModel的一个自然特性,如果用户碰巧有两个显示相同/相似数据的视图,我不必让我的模型对象进行通信更改。

答案 1 :(得分:7)

在我正在处理的项目中,每个视图都有自己的ViewModel,但是我们也有CollectionViewModel,它们由多个视图模型共享/引用。

思考 - 供应商列表,需要在您的应用程序的多个屏幕中显示 - 并且绑定到各种控件 - 列表框,网格视图,无论您需要什么。只有一个ViewModel可以简化供应商列表的更新/刷新逻辑。

TLDR:如果所有用例都以相同的方式使用ViewModel,我只会重用视图模型。即他们都使用相同的属性等。

答案 2 :(得分:4)

我会为每个视图分别创建一个ViewModel。未使用的属性使代码的可读性降低(如果未使用该属性,为什么会出现该属性?)。如果你对几个视图的一组固定属性具有相同的功能,我可以看到使用包含这些属性的基类。

答案 3 :(得分:2)

我通常共享ViewModels。据我了解,使用视图模型的优点是(a)安全性,应隐藏的属性和(b)业务层和表示层之间的关注点分离。 (b)在共享视图模型时完成相同的操作。

至于(a),我很少会在一个地方暴露财产是一种安全风险,而在另一地方则不然。如果需要隐藏属性,则可能需要隐藏在任何地方。当然,YMMV,但这似乎是一个相当主观的问题。

答案 4 :(得分:2)

每个视图肯定是一个ViewModel,imho。

随着应用程序复杂性的增加,共享的ViewModel将趋于增长,当一个具有50个属性的对象需要一个属性时,将它传递给一个视图并不好。

此外,有时您可能希望在ViewModel中添加绝对特定于View并且在其他视图中不需要的额外属性。假设您有一个依赖于ViewModel属性的CSS类。您可以在ViewModel中创建一个属性,而不是在View中编写if else语句,该属性根据您拥有的任何业务规则返回正确的css类。通过这种方式,您可以使View尽可能轻薄,并且使用专用的ViewModel,您不会与不真正关心它的Views共享CSS类名。

答案 5 :(得分:0)

我使用Entity Framework和Code First,所以我的域类需要保持相当严格,因为它们将被映射到sql数据库。

有些视图只使用一个直接映射的实体,这很好,所以我使用相同的域层实体。如果该实体需要更多信息(例如两个密码字段),我将使用组合。 '组合应该优于继承',所以如果你可以使用组合这样做,通常因为它只是附加属性,可以使用组合。

如果屏幕只使用该实体的两个属性,或者我想因安全问题而隐藏属性,我会创建一个新的视图模型并仅检索必要的数据。我将重用视图模型,但前提是在其他视图中需要相同的属性。

答案 6 :(得分:0)

TLDR:是的(如果您真的想使用它,并且知道如何明智地使用它)。

我可以想到视图模型层需要的三个职责:

  1. 将视图层和模型层耦合在一起
  2. 提供单元测试的界面
  3. 当单个页面很复杂时,将逻辑分成小块

第一个责任实际上与第二个责任冲突。 因为一旦视图模型知道(结合)视图类即可启动, 它不能进行单元测试。 知道要初始化的模型(及其提供者)类不会导致此问题。 但是,如果提供者是单身人士,则单元测试的“单元”数将减少。

当涉及第三种责任时,我将其称为路由。 例如,单击按钮后,用户应看到下一页。 这种逻辑应该位于哪一层? 视图?模型?当然不! 它无处可去,只能查看模型。 视图模型知道要启动的下一页的视图模型的类后, 它使巨型视图模型树得以处理。 因为这是递归发生的-下一页也知道下一页。 无论在此视图模型树中的哪个节点上, 一旦发生变化, 它反映在父节点上。 如何应对这些反思? 子类化? 请记住,在树中,一个节点可以具有数百个直接/间接子节点。

结论–仅当视图模型放弃第一个职责时,它才具有第三职责。 它真正擅长的唯一职责是第二责任。 但是,在这个问题下,我没有人提及它。