【问题标题】:Should I reuse view models in different views?我应该在不同的视图中重用视图模型吗?
【发布时间】:2012-08-25 16:50:22
【问题描述】:

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

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

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

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

你怎么看?您如何处理这种情况?

【问题讨论】:

    标签: c# asp.net-mvc viewmodel


    【解决方案1】:

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

    • 如果您希望模型/数据对象更加严格,那么您会倾向于将 ViewModel 与模型/数据联系得更紧密——即您将拥有一个在多个视图中使用的 ViewModel,并让 ViewModel 根据您要如何处理数据加载(并推迟图像或其他长时间加载的属性等)来确定要检索的属性。李>
    • 如果您希望您的视图更加严格,那么您可以将 ViewModel 绑定到更靠近视图的位置,即每个视图都有一个单独的 ViewModel,并让模型/数据对象在您从一个视图移动到另一个视图时处理诸如同步之类的事情。

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

            【解决方案5】:

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

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

            【讨论】:

              【解决方案6】:

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

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

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

              【讨论】:

                【解决方案7】:

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

                【讨论】:

                  【解决方案8】:

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

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

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

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

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

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

                  【讨论】:

                    猜你喜欢
                    • 2023-04-03
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-03-13
                    • 2013-05-07
                    • 2016-03-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多