【问题标题】:MVVM, UWP & Template 10 - Independency of model from view technologyMVVM, UWP & Template 10 - 模型独立于视图技术
【发布时间】:2018-01-11 03:28:19
【问题描述】:

我对 MVVM 的理解是,View 负责用户表示逻辑、交互逻辑的视图模型和 UI 独立模型类的特定数据转换,以及从数据的角度代表业务领域的模型本身。

关键是模型类应该是 UI 独立的。

这里出现了 UWP 开发模型和模板 10 BindableBase,模型类应该从中派生。它非常方便,但它将模型与特定的 UI 实现联系起来,即 UWP + 模板 10。

我有一个数据访问层吐出我想直接作为模型提供给 UI 的域对象。域相当复杂。我不想做的是在 UI 中重新实现数据域对象,也不想用 UI 特定的功能污染它。

对此有什么想法吗?

谢谢

【问题讨论】:

  • BindableBase 用于 ViewModel。在您的模型上实现 INotify 接口是可选的,您可以通过其他方式路由数据。
  • 除了以适配器的形式重新实现整个域之外,还有什么其他方法可以更新底层模型和触发更改事件?
  • 您真的那么需要模型中的更改事件吗?我会将它们作为不可变对象传递(这里和那里有一些例外)。当然,您的 ViewModel.Model 属性会触发该事件。
  • 嗯,基本上我最终是这样做的。但我不满意:)。

标签: mvvm uwp template10


【解决方案1】:

恕我直言,我认为您可能想错了。

MVVM 的目标是完全按照您的描述分离您的逻辑。这种分离的目的是简化您的代码。这是否使视图模型可测试并分离关注点?是的。但是,我认为这些是简单性的次要目标——它使您的代码易于管理和维护。

这是另一种说法。

MVVM 是 XAML 应用程序的绝佳方法。但是,如果 MVVM 没有使您的视图模型可测试或分离关注点,那么 MVVM 仍然是 XAML 应用程序的绝佳方法,因为它大大简化了代码——更小、更简单和隔离。

物有所值。

您可能会争辩说,MVVM 创建了另一层代码,开发人员必须先了解这些代码层,然后才能推理并为基础做出贡献。我会同意的。但我不会因此得出结论认为 MVVM 是不切实际的。与逻辑的其他耦合相比,增加的层是微不足道的。

现在回答你的问题。

您的数据层对象(可能是数据传输对象)与您的 UI 对象(可能是模型)非常相似。您的开发人员本能迫使您通过多态性、代码生成或接口将相似的东西联合起来,以避免增加错误、复杂性和测试的机会。

考虑一下。

在您的数据层中创建的对象是为您的数据层创建的。同样,在您的 UI 层中创建的对象也是为您的 UI 层创建的。结构相似性是领域相似性的副产品。当然,它们是相似的:然而,它们的意图却不同。为什么要合并它们?

你已经看到了问题。

您所拥有的唯一区别可能是数据层构造函数采用某种类型的数据读取器并填充属性。这对于数据层来说是完美的,但对于 UI 层来说是不合适的。您的 UI 层可能有消息事件或处理交互的自定义​​方法。这对于 UI 层来说是完美的,但对于数据层来说是不合适的。

那么,相似之处在哪里?

我认为开发人员(包括我自己)倾向于将相似的事物视为可能相同的事物。您的数据相关功能不属于您的 UI,也不属于其他方式。相反,您需要做的是看到相似之处,但要认识到它们是截然不同的对象,不应该被制作成相同的。

我们很懒。

重复代码与测试和错误无关。并不真地。这是关于我们作为开发人员如何如此痴迷于“更聪明地工作而不是更努力地工作”,以至于我们倾向于看不起“努力工作”。如果一个对象是为一个层构建的,它应该在该层中,而不是由另一个层共享。我强烈地感觉到这种方式。

正确的解决方案

最简单的解决方案是让您的 DTO 在数据层从 DataLayer.Object 序列化,然后在 UI 层将其反序列化为 UILayer.Model。这是最简单和最简单的方法,并且充分允许您强制数据和对象 API 供其唯一层使用。

这意味着有两个几乎相同的对象:一个在数据层,一个在 UI 层。但这并不意味着有两个相同的对象。它们并不相同,因为它们具有每一层、每一层所独有的功能。

如果没有功能怎么办?

想知道这是否适用于没有附加功能的对象和模型是有意义的。我坚信没有添加功能的任何层中的对象和模型只是在等待添加该功能。如果您假设不存在并基于该假设进行构建,您将迫使您或即将到来的维护开发人员永远不要添加特定于层的功能。

这有关系吗?

我认为是的。为什么?因为对象或模型中的特定于层的功能允许我在数据对象或模型的上下文中向我的架构和实现添加复杂性(而不是复杂性),而不是像managerhelper 这样的外部构造,或utility。毫无疑问Type.DoSomethingHelper.DoSomethingForType(Type) 容易。

其实我有三个

您知道,我是这样做的:在我的项目中,您和我可能有相似的数据层/服务。但是,我的 UI 层实际上有两个模型——不是一个。 (假设 Users 是数据类型。)我的 UI 层有 json.UserModels.Userjson.User 是一个简单的结构,从我的服务中反序列化,并且与服务对象完全匹配。但我的 UI 很少需要服务 API 表面/结构。

服务(DataLayer.User)> |净 | > UI(json.User > Models.User)

那么,json.User 用于创建 Model.User,其结构完全符合我的 UI 层的需求——包括方法、事件和消息传递结构。我可以随意更改我的Models.User,因为我也向我的 UI 添加了功能 - 包括合并来自其他/新数据服务的数据。此外,Model.User 可以实现INotifyPropertyChanged,其中数据层对象和json 对象永远不会(或不需要)。

考虑一下

如果您将模型分开并防止一个代码库不正确地影响另一个代码库,那么您的数据库或数据服务/层的任何更改都不需要更改您的 UI 层,即使您更改了 API 表面.只有json.User 对 UI 层中反序列化提示的更改或调整会受到影响。对我来说,这才有意义。

但是测试和错误呢?

测试很少测试结构。数据结构是您可以添加到解决方案中的最简单的东西,并且很少会增加复杂性。你可以在一秒钟内推理出一个结构。您可以在大约一分钟内推理出一种方法。结构的成本非常低。他们的建设成本也很低。如果你将初始结构从数据层复制/粘贴到 UI 层——这就是我们所做的。但这不是重复代码。它只是构建适当解耦的类似对象。

我就是这么想的。

【讨论】:

    猜你喜欢
    • 2021-05-30
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 2019-06-12
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多