繁体   English   中英

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

[英]Should I reuse view models in different views?

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

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

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

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

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

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

  • 如果你喜欢你的模型/数据对象更严格,那么你会倾向于将 ViewModel 与模型/数据联系得更近——也就是说,你将有一个在多个视图中使用的 ViewModel,并让 ViewModel 确定哪些属性根据您希望如何处理数据加载进行检索(并推迟图像或其他长时间加载属性等)。
  • 如果您希望您的视图更加严格,那么您可以将 ViewModel 与 View 联系在一起,即每个视图都有一个单独的 ViewModel,并让模型/数据对象在您从一个视图移动到另一个视图时处理诸如同步之类的事情。

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

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

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

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

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

每个视图肯定有一个 ViewModel,恕我直言。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM