ViewModels和渲染

6
在几个示例项目中,我看到ViewModel被用来将数据对象转换为字符串,以便在View中使用。
ViewModel通常具有一个构造函数,接收一个参数 - 数据对象。然后构造函数会填充ViewModel的各种属性(大多是字符串和整数)。
这可以防止View中出现任何复杂的逻辑。
乍一看,这对我来说似乎是个好主意,因为它更全面地将View与复杂逻辑分离开来。
例如,假设我的View试图呈现数据对象的属性“大小”,其中Size是一个介于1和3之间的数字,代表“小/中/大”。
我不需要在View中使用if/switch语句,我只需要在ViewModel中使用“SizeString”或类似的东西,if/switch语句会在ViewModel构造函数中执行。
有人反对这种方法吗?
是否更好使用其他方法,例如helpers?如果是这样,为什么?
2个回答

6
ViewModel的目的是将复杂的Domain Model分解为可以以某种形式呈现的基本元素(部分)。这种分解必须在某个地方进行。它可能涉及一些简单的逻辑,例如将离散值(OK、warning、error)转换为颜色(绿色、黄色、红色),这是ViewModel的本质。因此,我的默认方法是将这种逻辑封装到ViewModel本身中。考虑另一种选择:如果不在ViewModel中实现,那么在哪里实现呢?如果将逻辑放在其他地方,你最终得到的ViewModel基本上只是一个没有逻辑的结构。让ViewModel封装Domain Object的转换/分解很好地符合单一职责原则。虽然这是我的默认方法,但我始终意识到这种逻辑可能需要在多个ViewModel之间重复使用。在这种情况下,这可能表明原始的ViewModel实际上是由几个子视图组成的复杂ViewModel。在这种情况下,你可以将通用逻辑提取到一个子ViewModel中,该ViewModel仅封装了那个小部分。

很好的解释。我之前不确定的原因是,我确信在某个地方读到过ViewModel应该只是普通的POCO对象,没有任何逻辑。但显然这样行不通。ViewModels应该允许包含表示逻辑。 - Jonathan
POCO并不排除逻辑的存在 :) - Mark Seemann
想写关于SRP的内容,但你已经写了。就像我经常说的那样 - 同时成为拳击手和芭蕾舞者很难。 :) - Arnis Lapsa
我们发现,创建与视图控件/数据相关的POCO ViewModel,然后将所有映射/转换逻辑放在单独的映射器类中更容易。这样可以更好地重用简单映射,同时减少开发人员在视图中开始放置更复杂的调用的机会(我们所做的唯一函数调用是对Html助手类的调用)。 - Beep beep
有趣的想法。我也听说过从域对象复制属性,然后使用像“AutoMapper”这样的框架将数据自动转移到ViewModel中。 - Jonathan

2
它将所有内容转换为字符串,因为Web中的所有内容都是字符串。
基本上,视图模型应处于“准备输出”状态。如果Web仅由数字组成,则我们将所有内容转换为int / decimal。
viewModel的整个重点在于格式化可表示的数据。对于您的情况-大小枚举为small / medium / large。这并不是从视图中分离逻辑使其有价值的原因-而是能够在一个地方以一种方式适应您的Web数据。
回答评论=> 是的,那很好。我也在做同样的事情。但需要提到的是-我不反对将其放入视图中。因为视图和视图模型是“依赖链”的最后一个。我非常务实,并完全反对只有在开发人员将域模型用作视图模型并且视图模型的要求与域模型冲突时才使用“域对象”的情况。

实际上,我已经将其实现为枚举类型,但是我排除了这个事实,以免过于复杂化示例。当然,如果我直接让视图访问枚举类型,仍然需要一些逻辑将其转换为字符串,例如:"Enum.GetName(...)"。因此,我仍然更喜欢在ViewModel中将属性公开为字符串,并让ViewModel负责枚举-字符串的转换。你认为这样可以吗? - Jonathan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接