MVVM - 模式和实用性
Posted
技术标签:
【中文标题】MVVM - 模式和实用性【英文标题】:MVVM - Patterns and Practicality 【发布时间】:2015-11-04 19:57:28 【问题描述】:我在 WPF 中使用 MVVM 已经有一段时间了。而且我在开发过程中学到了很多东西(从不使用它到开发了几个应用程序)
但是,最近我遇到了一些针对代码的 cmets,这让我想知道我是否以正确的方式做事。我当前的设置(大致)是这样工作的:
Model - 负责存储数据,使用数据验证 IDataErrorInfo 和脏跟踪 ViewModel - 负责获取数据(从像 模式)并对其进行格式化以供视图使用(例如 过滤、排序)也负责从 查看(保存、加载、过滤器更改等) 视图 - 常见的 UI 内容现在有人向我提到我应该从不在模型中包含业务逻辑,并且模型应该尽可能薄,视图模型应该负责处理诸如数据验证之类的事情和脏跟踪。
我在这方面看到了 cmets 和批评,人们反对和支持将逻辑放入模型中,我还没有看到这些笼统陈述的任何实际原因。所以我很想知道我是否应该重构我的设置。
此外,鉴于我确实将逻辑移至视图模型,我可以看到需要拥有多个视图模型,而我目前只有一个,例如:
Person
- 型号
PersonViewModel
- 处理脏跟踪、数据验证等
PersonsViewModel
- 处理获取 PersonViewModels 的集合,
过滤等
PersonsView
- 用户界面
这似乎有点多余,但也许我误解了一些东西。我真正在寻找的是以某种方式执行此操作的一些实际原因,或者这是另一个论点,例如在 MVVM 中使用代码隐藏(纯粹的观点,没有什么理由等)
【问题讨论】:
您说 VM 负责获取数据。这可能是真的,也可能不是。这取决于什么最适合您,但 MVVM 设计模式确实指定了它。例如,在创建第一个视图模型之前,您可以在应用程序启动时加载所有数据。或者您可以称您为模型,其中包括来自视图模型的数据访问。 这只是我当前的设置,我的视图模型负责与存储库通信,而存储库又与 WCF 服务通信,但我有其他应用程序的工作方式不同。 “模型内部永远不会有业务逻辑” - 以前从未听说过与 MVVM 相关的内容;阅读此类文章/讨论会很有趣。 在典型的互联网时尚中,我终生无法找到我读过的那篇文章。我可以找到一句话永远不要把它放在视图模型中。虽然我提到接收的 cmets 不在线。 【参考方案1】:MVVM 的高级描述:
视图:用户界面
模型:业务逻辑和数据(例如领域模型+存储库,或者事务脚本+POCO实体等)
ViewModel:数据以这种形式发布到视图,很容易从视图中消费。***的定义说:视图模型是视图的抽象,它公开了公共属性和命令。
我喜欢 Practical MVVM Manifesto (archived version) 原则:简单性、可混合性、可设计性、可测试性。
这是非常高级和抽象的描述,这就是为什么您可能会发现许多 MVVM 变体。无论您选择哪种 mvvm 样式,请牢记责任和原则,您应该没问题。尽量避免复杂性。 MVVM 不是灵丹妙药,单一设计模式无法涵盖所有场景。一种 mvvm 实现可能适用于一种应用程序,但不适用于另一种应用程序。例如,我为每个新项目从头开始构建我的 mvvm 架构,以确保最适合
当涉及到责任时:
以验证为例: 密码和重复密码输入应该相等的验证逻辑显然是表示逻辑,应该出现在视图模型中。另一方面,可能存在业务规则,即密码必须包含至少一个特殊字符。这个逻辑应该驻留在模型中,但是您可以在视图模型中公开它以便从视图中轻松使用。这是一个业务逻辑,但您可能需要以某种方式呈现它。
如果您的应用程序仅使用 Web 服务来检索和存储,那么您的模型可能只是数据访问组件。
这里有几个资源:
***:https://en.wikipedia.org/wiki/Model_View_ViewModel.
MVVM 是 Martin Fowler 的 MVP 模式的变体,您可能会发现它也很有用:http://martinfowler.com/eaaDev/PresentationModel.html
MSDN(模式与实践):https://msdn.microsoft.com/en-us/library/hh848246.aspx
【讨论】:
谢谢,这是一个全面的答案,您认为 IsDirty 跟踪是视图模型还是模型的责任?目前我在模型上有它,但有人告诉我这是视图模型的责任。 @user1412240 好的。为什么你需要了解脏污?总的来说,我发现划分逻辑的一个好方法是重用和测试。该模型是业务逻辑,即使您编写 MVC 网站也应该可用。 VM 和 V 之间的区别在于 VM 是可单元测试的。 好吧,看到这一切后想一想,我猜这将是 VM 角色,因为我使用 IsDirty 启用保存按钮,阻止导航而不保存(或至少通知用户)。都是一个接口级逻辑 嗯,这取决于。如果您的 PersonViewModel 只是公开了已经具有 changetracking 的 Person 模型,并且您直接绑定到 Person,那就没问题了。在其他情况下,您可能只想在单击保存按钮时更新 Person 的属性。如果您只想在某些内容发生更改时启用保存按钮,则需要在 viewmodel 中实现更改跟踪。我建议从最简单的方法开始,它不会破坏高级 mvvm 原则,但要为变化做好准备。 抱歉,回复晚了,我没有收到此评论的通知。我总是为变化做好准备,这就是导致我提出这个问题的原因哈哈,我认为我更喜欢 VM 上的更改跟踪,因为更改跟踪不会在 WPF MVVM 应用程序之外使用,因此不属于模型 【参考方案2】:我喜欢将模型层视为与应用程序托管方式无关的任何事物(即独立于 WPF)。它是一个或多个 dll,代表业务领域和需要在其中执行的操作。如果获取这些相同的 dll 并在 Web 应用程序、Windows 服务等中使用它们是有意义的,那么这通常表明模型和 ViewModel 之间的拆分是适当的。
【讨论】:
对,如果我理解正确的话。您的原因是可重用性,以及跨服务层使用相同模型类的能力。好的,这是我可以落后的一个很好的理由,谢谢 在概念上是的。毕竟 MVVM 中的“模型”与 MVC 和许多其他设计模式中的模型相同。您可能对here 的意见感兴趣 - 关于 MVC 的类似问题。 有趣,这与我收到的关于将逻辑排除在模型之外的 cmets 的反面,但再次对我来说答案很有意义。看来这一切都归结为个人喜好和应用程序的需求。我想我的困惑是需要额外的没有视图的视图模型(我一直明白视图模型仅用于视图) 我完全同意这一点,尽可能多的业务逻辑应该放在模型中,只是想发布完全相同的推理。 “将逻辑排除在模型之外”-也许他们在谈论将逻辑排除在实体之外-关于贫血的实体。这意味着实体没有任何行为。在一些简单的场景中,行为可能纯粹在视图模型中,但更复杂的场景需要重用行为,并且您需要创建某种表示行为的业务类 - 例如事务脚本。请注意,实体与模型不同。在这种情况下,模型既是贫血实体,也是交易脚本。【参考方案3】:您的问题没有简单的答案。最简单的答案是模型和视图模型应该包含您应该单元测试的代码。模型和视图模型之间的分离不太明显。我喜欢使模型尽可能简单,并将其限制为与服务器层交换的任何内容。视图模型应该封装模型,并提供任何附加功能(业务逻辑和抽象表示逻辑),以便您可以保持表示层尽可能简单(声明性,在 WPF XAML 的情况下)。
【讨论】:
您喜欢保持模型纤薄的事实仅仅是个人选择吗?这是否也意味着我对多个视图模型的假设是您选择做事的方式? 这是个人选择和对该主题的研究的混合体。是的,我经常有多个视图模型用于单个模型 - 视图模型是特定于视图的,而模型更通用。 只是一个快速的清理,你会说我的例子(Person、PersonVM、PeopleVM)是你会做的吗?鉴于此时没有personview? 在不知道各种模型包含哪些数据的情况下,我会说是的。虽然,如果人员视图的唯一目的是显示 Person 中包含的数据,那么 PeopleVM 包含 Person 模型列表可能就足够了。 是的,我可以接受,这个想法就是我想在那个视图中编辑的内容,直接从 gridview 说,你几乎回答了这个问题。谢谢。【参考方案4】:我是这样看的:
Model - 可以传递的对象。用于通信的不同层之间的通用类型。
ViewModel - 专为视图创建。这应该包含 UI 逻辑,例如,数据注释等将放在此处。您也可以在这里调用您的 Web 服务方法(假设您的实际业务逻辑位于外观层中,或者您的数据库逻辑位于不同的层/项目中)来填充视图、下拉列表等。您最终可能会得到多个这些查看,具体取决于您的设计。
查看 - 仅限用户界面。
我不怕在 ViewModel 中进行外部调用
【讨论】:
好吧,这一切都是有意义的,似乎是主要的思想流派,但是拥有一个没有相应视图的视图模型又有什么意义呢? 一个 ViewModel 可能指向某种控制器。该控制器是主视图的一部分以上是关于MVVM - 模式和实用性的主要内容,如果未能解决你的问题,请参考以下文章
Silverlight实用窍门系列:47.Silverlight中元素到元素的绑定,以及ObservableCollection和List的使用区别