Welcome

首页 / 软件开发 / 数据结构与算法 / 视图模型(View-Model)到底是什么

视图模型(View-Model)到底是什么2013-01-17 infoq 译:姚琪琳在 “视图模型(View-Model)”这个术语出现之后,很多开发者都有不少疑问。视图模型需要处理视图、模型和外部服务间 的交汇的问题,这一点是清晰的,但准确的做法却往往被一笔带过。它应该包含哪些内容,不应该包含哪些内容,没有清晰的列 表,它们往往最终会成为所有东西的大杂烩。本文无意给出明确的答案,而是要探索视图模型所承担的众多角色中的几个。

在你阅读本文中的不同角色和模式的时候,请记住以下三点:

这些示例都来自真实项目。

大多数视图模型都会承担多个角色。

严格遵守某个模式的重要性低于可运行的程序。

模型端的角色

为视图提供数据是视图模型至关重要的角色。然而,即便仍然使用XAML数据绑定技术,提供数据的方式 也是多种多样的。

用视图模型替代数据上下文

用视图模型替代数据上下文是最简单的模型端(model-side)模式 ,可能也是最常见的。真正的数据通过视图模型的一个或多个简单的属性暴露出来。 在某种程度上,这并不是模式。它只是将 视图模型和视图的真正数据上下文属性关联起来,并且注入其他功能,如包装导航或服务调用的ICommand。本文后面还会讨论这 个话题。

将视图模型作为活动记录

遗憾的是,“将模型作为活动记录(Active Record)”是一个常见的错误模 式。在这种模式下,应用程序中没有真正的模型。相反,所有的字段都由视图模型本身直接提供。 例如,CustomerViewModel可 能包含FirstName、LastName、CustomerId字段。由于这是一个视图模型,所以很可能还挂接了外部服务。可以通过 LoadCustomerCommand和SaveCustomerCommand等ICommand将他们暴露出来,这就将视图模型成功地转变成活动记录。

需 要注意的是,活动记录模式本身在某些场景下是相当有效的。问题是,活动记录的用途一定程度上被夸大了,若再让它们担任视 图模型的其他角色,就几乎成了“万能对象(god object)”。

如图所示,单元测试 没有安身之处。你可以通过使用附带模拟(mock)服务的集成测试来创建虚拟的单元测试,但这种方法往往非常耗时,并且容易 出错。

如果没有模型,就不是MVVM。

将视图模型作为适配器或装饰器

视图模型可以作为适配器(adapter )或装饰器(decorator),以临时包装一个模型,提供额外信息或新格式。然而,这是非常危险的实践,只要有可能就应该避 免。

我们使用经典的FullName来作为示例,这样做会带来两种风险。

基于推送的包装器

在基于推送的包 装器(wrapper)中,我们假设只有视图模型能向视图推送数据更新。

public class PersonViewModel : INotifyPropertyChanged{private readonly Person m_Model;public PersonViewModel(Person model){m_Model = model;} public string FirstName{get{ return m_Model.FirstName}set{m_Model.FirstName = value;OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));OnPropertyChanged(new PropertyChangedEventArgs("FullName"));}}
这意味,如果不通过PersonViewModel包装器而直接更改模型,此操作就会失败。这些更改不会传播到视图,导致同步 问题。