15

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

您是在多个视图上共享这样的视图模型,还是为每个视图创建单独的视图模型,或者您更喜欢继承组合策略?

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

  1. 最小惊喜原则:一个视图模型只填充5个属性的2个并得到空引用异常是很奇怪的,因为你不想查询数据库的额外数据。当视图模型有 5 个属性时,我希望所有属性都被填充。例外证明了规则。
  2. 关注点分离/单一职责原则:视图模型在复杂的站点上杂乱无章,因为您必须满足每个视图的不同需求。如果涉及逻辑,它也会变得更加复杂。

你怎么看?你如何处理这样的情况?

4

8 回答 8

11

人们倾向于根据他们的使用角度对 ViewModel 有不同的理念。ViewModel 是视图和模型之间的粘合剂,人们通常会根据他们喜欢更严格的两端中的哪一个来回答。

  • 如果您希望您的模型/数据对象更严格,那么您将倾向于将 ViewModel 更接近模型/数据 - 即您将拥有一个用于多个视图的 ViewModel,并让 ViewModel 确定哪些属性根据您希望如何处理数据加载(并推迟图像或其他长时间加载属性等)进行检索。
  • 如果您希望您的视图更加严格,那么您将把 ViewModel 绑定到更靠近视图的位置——即每个视图都有一个单独的 ViewModel,并让模型/数据对象在您从一个视图移动到另一个视图时处理诸如同步之类的事情。

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

于 2012-08-30T22:00:15.893 回答
8

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

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

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

于 2012-08-30T21:48:24.290 回答
4

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

于 2012-08-30T21:42:29.530 回答
3

绝对每个视图一个 ViewModel,恕我直言。

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

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

于 2012-08-30T22:16:05.717 回答
2

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

至于(a),我很少遇到暴露财产在一个地方存在安全风险但在另一个地方没有安全风险的情况。如果一个属性需要隐藏,它可能需要到处隐藏。当然,YMMV,但这似乎是一个相当主观的问题。

于 2012-08-30T21:45:36.953 回答
0

我将实体框架与 Code First 结合使用,因此我的域类需要保持相当严格,因为它们将被映射到 sql 数据库。

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

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

于 2012-08-30T21:47:57.220 回答
0

仅当所有视图都使用所有属性变量和方法时,我才会在多个视图之间共享一个 VM,否则我将使用继承和抽象基础视图模型,如果这不能解决。做1对1

于 2017-11-24T17:47:33.310 回答
0

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

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

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

第一个职责实际上与第二个职责相冲突。因为一旦视图模型知道(耦合)要启动的视图类,它就不能进行单元测试。知道要启动的模型(及其提供者)类不会导致此问题。但是,如果提供者是单例,则单元测试变得不那么“单元”。

说到第三个职责,有一种逻辑我称之为路由。例如,单击按钮后,用户应该会看到下一页。这种逻辑应该在哪一层?看法?模型?当然不!除了查看模型,它无处可去。一旦视图模型知道要启动的下一页的视图模型的类,它就会生成一个巨大的视图模型树来处理。因为这是递归发生的——下一页也知道下一页。无论在这个视图模型树中的哪个节点上,一旦发生变化,它就会反映在父节点上。如何处理这些反射?子类化?请记住,在树中,一个节点可以有数百个直接/间接子节点。

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

于 2020-07-27T10:51:44.770 回答