20

根据当前的实践(至少使用 WPF 和 Silverlight),我们看到通过视图模型中的命令绑定绑定的视图,或者我们至少看到在视图模型中处理的视图事件。这似乎违反了SRP,因为视图模型不仅对视图状态建模,而且对视图(用户)做出响应。其他人询问如何在不违反 SRP 的情况下构建视图模型,或者询问他们的实现是否这样做(最后一个是 MVC 中的控制器,但大致类似)。

那么当前的做法是否违反了 SRP?还是“视图模型”真的是不违反 SRP 的东西的集合?稍微解释一下,似乎我们需要知道什么是单一职责,或者如果概念中有多个职责,是否将个人职责拆分出来,符合 SRP。我不知道。

维基百科对视图模型的定义说

[T]ViewModel 是“视图的模型”,这意味着它是视图的抽象,也用于视图和模型之间的数据绑定

这对于 SRP 来说似乎已经足够好了,但后来的条目说(我强调了)

[ViewModel] 充当数据绑定器/转换器,将模型信息更改为视图信息并将命令从视图传递到模型

在一篇关于视图模型角色的Prism 博客文章中,作者说(再次强调)

它归结为视图模型是以下内容的组合

  • 视图的抽象
  • 命令
  • 价值转换器
  • 查看状态

我确定我错过了许多定义,但它们似乎属于以下类别:

  1. 建模视图状态的单一“模糊”责任(所以我们所说的状态是什么 意思
  2. 多重职责(视图状态、用户交互(即命令))
  3. 单一特定职责(抽象、状态、交互、转换)的组合,因此具有单一职责:“管理所有这些东西”。

如果你很好奇,我“关心”这个,因为(2)感觉不错,但似乎与流行的实现背道而驰。

4

4 回答 4

11

Martin 定义的单一职责:

“改变班级的理由不应该不止一个。”

就 MVVM 而言,ViewModel 实际上只是Presentation Model的专门实现。

因此,尽管有人认为Presentation Model应该只代表 UI 的状态Presenter/Controller应该始终代理 UI 和 Presentation Model 之间的命令。如果遵循这一想法,将SRP 划分为 State 和 Commands,那么添加命令不应影响表示状态的类。因此 MVVM 会破坏 SRP。

然而...

我认为这是在抓住稻草。MVVM 是一个相当专业的实现,主要用于 WPF/Silverlight(现在是浏览器客户端)。

模式旨在使设计更简单,而替代方案会更麻烦或更不易维护。由于 MVVM 旨在利用表示技术极其丰富的数据绑定功能,因此这是一个值得权衡的选择。

于 2011-08-23T17:05:21.263 回答
6

不!MVVM 不违反 SRP,(程序员这样做了,哈哈!)

没有理由使用 MVVM 模式需要忽略 SRP。MVVM 并不意味着只有一个 Model Class、一个 View-Model Class 和一个 View Class。当然,如果你只有一个 View Class,你就只能显示一个简单的屏幕。

视图层中的那些类应该负责一件事;做、决定或包含。一个视图可以由几个子视图组成,它们的工作是完成某些用户交互。考虑一个基本表单,它有一个显示网格,网格中的项目可以编辑,并且有一个“保存”按钮。

主视图将是其他两个视图的容器;数据网格(用户控件或其他东西)和命令控件。然后数据网格负责选择正确的子视图来呈现数据;从本质上讲,它是一个数据绑定的容器。用于编辑项目的视图是数据网格的子视图,而数据网格又是主视图的子视图。最后,命令控件是一组按钮(在本例中为单个按钮),其唯一职责是发出用户已发出命令的信号。

通过这种方式,编辑视图(由 DataGrid 使用)对于使用它的内容是不可知的,并且有一个责任;与命令控制相同。同样,DataGrid 不关心谁使用它,只关心它可以包含编辑视图(子视图)。那里的 SRP 不错。

与视图(和子视图)匹配的视图模型也负责一件事。编辑视图模型是编辑视图绑定的容器;它只包含可以显示/编辑的数据字​​段。它不关心任何事情,只关心其属性之一发生变化时的信号。命令按钮视图模型是一个做事的类。它的命令绑定到按钮,它会根据用户点击的内容来工作。它必须有权访问 ViewModel(s) 的其他部分才能完成工作。

主页视图模型在那里包含其他子视图。它的唯一职责是作为初始化器,创建所有必需的 ViewModel 实例,并将构造函数参数传递给其他 ViewModel 实例(例如,命令按钮视图模型,以便它知道从哪里获取数据以进行工作)

将一大堆功能塞进一个大视图将绑定到的单个 ViewModel 是很自然的。但不一定非得如此,SRP 可以在 MVVM 中维护。

MVVM 的主要目标是允许可测试的设计,Model 层可以独立测试,Model 中的所有类都可以轻松遵循 SRP。ViewModel 可以在不需要视图的情况下进行测试;在 ViewModel 中考虑 SRP 变得更加棘手,但它肯定是可行的;只要记住打破你的课程,这样他们就只有一个问题。View 必须与 ViewModel 分开,如果运气好的话,您对 ViewModel 的测试会使捕捉 View 变得超级容易。请记住,您可以让每个 View-let 都遵循 SRP,成为更大的综合视图(容器)的一部分。

TL;博士?为了直接回答您的问题,视图是不破坏 SRP 的类的集合。因此,当 ViewModel 从 View(s) 中抽象出来时(View-First),它们也是遵循良好 SRP 的类的集合。

于 2011-08-23T21:39:05.940 回答
6

我认为当前围绕 MVVM 的许多做法(至少)违反了 SPR。这是另一种情况,只需将控制器添加回 MVVM 即可干净地解决所有问题。我称之为 MVCVM :)

我们在所有最近的项目中成功使用的模式是在模块中注册控制器,并在启动时初始化它们。控制器非常轻巧/纤薄,是应用程序在监听或发送消息的整个生命周期中唯一需要保留的东西。然后在他们的初始化方法中注册他们需要拥有的任何东西(视图和视图模型等)。这种轻量级的仅内存逻辑模式也使应用程序更轻薄(例如,对于 WP7 更好)。

正如您所发现的,仅使用 VM 的问题在于,最终您遇到了他们需要了解视图、命令或其他不应该涉及自尊的 ViewModel 的东西的情况!

我们遵循的基本规则是:

  • 控制器根据事件做出决策
  • 控制器获取数据并将其放置在适当的视图模型属性中
  • Controllers 设置 View Models 的 ICommand 属性来拦截事件
  • 控制器使视图出现(如果在其他地方没有暗示)
  • 视图模型是“愚蠢的”。用于绑定的保留数据,仅此而已
  • 视图知道它们显示某种形状的数据,但不知道它来自哪里

最后两点是你永远不应该打破的,否则关注点分离就会消失。

简单地将控制器添加回 MVVM 组合似乎可以解决我们发现的所有问题。MVVM 是个好东西,但为什么它们不包括控制器呢?(但这当然只是我的意见):)

于 2011-08-24T09:51:31.233 回答
2

它归结为视图模型是以下内容的组合:

  • 视图的抽象
  • 命令
  • 价值转换器
  • 查看状态

我不明白您为什么将前两项分开。命令是视图的一部分。

至于其余的 - 你是对的。在某些情况下。我已经构建了应用程序,其中值转换和维护视图状态的任务非常复杂,以至于单个视图模型类无法完成所有工作,我将它们分解为与 VM 互操作的单独类。

所以?

于 2011-08-23T17:24:58.140 回答