关于一般的视图模型设计概念,我现在有一个相当大的困境。我的意思是一般,就像它不完全绑定到一个给定的语言或环境:我有同样的困境,当我为Winforms, WPF或KnockoutJS写视图模型。
作为一个简化的用例,假设我有一个视图,我必须从两个选择框中选择一个国家和一个城市。两者都在数据库中表示为一个惟一的ID、一个Name和一些其他相关信息,比如人口。现在假设我必须以文本形式呈现当前选中的数据,例如视图的标题为"您选择了伦敦,英格兰"。现在,这里是我创建视图模型的两个备选方案,我将尝试在每个版本下面列举我已经想到的优点/缺点。代码是以一种伪方式编写的,以便尽可能地通用。
class RegionModel {
ID: number;
Name: string;
Population: number;
}
版本1:存储选中的对象
class MainView {
SelectedCountry: RegionModel;
SelectedCity: RegionModel;
SelectionInfo: string; // computed, should return the "You've selected ...." caption
Countries: List<RegionModel>; // datasource for country select
Cities: List<RegionModel> // datasource for city select
}
优点:
- 由于被选中,所以简单易懂项目的类型与可选择项目的类型相同。
- 很容易计算这样的信息,如"你已经选择…"因为所有的当前选中项目的成员直接出现。
缺点:
- 它保存了比消费者API通常需要的更多的信息。通常它只需要ID。
- 如果在客户端应用中使用,整个被选中的对象将被返回到服务器,占用带宽。
- 如果消费者API只需要ID(像在大多数情况下),我必须在我通过之前解决某种转换。可能在web应用中例如,在序列化到JSON期间。
版本2:只存储所选项目的ID
class MainView {
SelectedCountryID: number;
SelectedCityID: number;
SelectionInfo: string; // computed, should return the "You've selected ...." caption
Countries: List<RegionModel>; // datasource for country select
Cities: List<RegionModel> // datasource for city select
}
优点:
- 它的效率在于它只包含需要的信息是消费者api最有可能需要的。
- 无需额外转换,可高效通过对于服务器端或其他API几乎是"原样"的。
缺点:
- 在我看来,不是那么简单易懂。
- 如何计算信息字符串?我需要,现在更难了从选择源列表中获取所需的成员根据给定的ID进行搜索,因此它在很大程度上依赖于这些清单(我的意思是项目必须在那里)。
我希望它不会因为没有建设性而迅速关闭。任何形式的建议,想法或经验将不胜感激。此外,如果答案是"视情况而定",请试着给我一些点,在哪里和什么时候使用哪个。
更新我想我的问题有点不清楚。我知道将视图模型与数据库实体解耦,这里我没有提到数据库实体。我提到了一个"抽象消费者API"。在一个具体的场景中:如果API需要所选项目的名称,而我的API只需要id,我应该选择哪一个替代方案,应该在哪里进行转换?例如,我的服务器期望这样的数据格式(JSON):
{
"SelectedCountryID": 2,
"SelectedCityID": 5
}
,没有别的了。我怎样才能优雅地处理它呢?我希望通过手动转换来避免重复。
根据您的数据源的实现方式,这可能没有什么区别:如果您正在检索国家和城市列表,您可以存储对所选值的引用,对其字段之一的引用或列表中的索引。
忽略这一点,您应该将视图模型实体与数据库实体解耦,并仅将视图所需的字段放入视图模型中。这样,您的信息流量最小化,您的代码受数据库更改的影响更小。
在OP更新后编辑
说到与API交互而不是与数据库交互,我认为你可以应用同样的想法,只是用"服务层实体"替换"数据库实体"(例如,JSON进出你的服务器)。将返回的数据放入视图模型对象中,保存您需要的那些属性。显然,您可能还需要存储id
,如您所述,当您稍后需要引用同一实体时。
从理论的角度来看,您不应该包含视图未使用的任何其他字段,但您可以根据自己的需求这样做。例如,当您需要将这些字段传递回服务层,并且不希望通过id
再次查询以检索服务实体时。然而,也有其他替代方案(例如,某种缓存),确切的平衡取决于您的需求。
基于MVVM模式,你的viewModel应该是一个具有你需要在视图中显示的所有属性的对象。ViewModel应该只用于严格绑定到视图。不管怎样,你的例子在我看来不是很好。你不应该在存储东西的情况下考虑viewModel,请更多地考虑呈现数据。
请记住,在数据库中有数据之前,您必须插入它。所以,如果你有一些表单,有名字和姓氏,用户首先必须填写这个表单,数据必须插入到数据库中,没有它,你就没有任何ID。
总而言之,我认为viewModel应该具有必须呈现给最终用户的属性。