当前的MVVM视图模型是否违反了单一责任原则?

Kit*_*Kit 19 silverlight wpf single-responsibility-principle mvvm viewmodel

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

那么目前的做法是否违反了SRP?或者"视图模型"真的是一组不违反SRP的东西?为了解决这个问题,似乎我们需要知道什么是单一责任,或者如果概念中有多个责任,个别职责是否分开,符合SRP.我不确定.

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

[View] ViewModel是一个"视图模型",意思是它是View的抽象,也用于视图和模型之间的数据绑定

对于SRP而言,这似乎已经足够了,但后来这篇文章说明了(我强调了)

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

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

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

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

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

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

如果你很好奇,我"关心"这个因为(2)感觉正确,但似乎与普遍的实施相反.

Jos*_*osh 11

马丁定义的单一责任:

"从来没有超过一个改变的理由."

就MVVM而言,ViewModel实际上只是一个Presentation Model的专用实现.

因此,虽然可以认为表示模型应该仅表示UI 的状态,并且演示者/控制器应该始终在UI和表示模型之间代理命令.如果遵循这个想法,使用SRP划分状态和命令,则添加命令不应该影响表示状态的类.因此MVVM会破坏SRP.

然而...

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

模式旨在使设计更简单,其中替代方案将更加麻烦或更难以维护.由于MVVM旨在利用演示技术的极其丰富的数据绑定功能,因此这是一个值得的权衡.


Eth*_*gon 6

没有!MVVM没有违反SRP,(程序员呢,哈哈!)

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

View层中的那些类应该负责一件事; 做,决定或包含.视图可以包含多个子视图,这些子视图的作业是执行用户交互的某些部分.考虑一个基本形式,它有一个显示网格,网格中的项目可以编辑,并有一个"保存"按钮.

主视图将是另外两个视图的容器; datagrid(用户控件或其他东西)和命令控件.然后,datagrid负责选择正确的子视图以呈现数据; 在essense它是一个数据集的容器.编辑项目的视图是数据网格的子视图,而后者又是主视图的子视图.最后,命令控件是一组按钮(在这种情况下是单个按钮),其唯一的责任是引发用户已发出命令的信号.

通过这种方式,编辑视图(由DataGrid使用)与使用它的用途无关,并且有一个责任; 与命令控件相同.同样,DataGrid并不关心谁使用它,只是它可以包含Edit View(child).尼斯SRP那里.

ViewModels匹配Views(和children)也是一件事.编辑视图模型是编辑视图绑定的容器; 它只包含可以显示/编辑的数据字​​段.当它的一个属性发生变化时,它并不关心任何事情.命令按钮视图模型是一个可以完成任务的类.它的命令绑定到按钮,它将根据用户点击的内容工作.它必须能够访问ViewModel的其他部分才能完成它的工作.

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

将大量功能塞入大型View将绑定的单个ViewModel中是很自然的.但它不一定是这样,并且可以在MVVM中维护SRP.

MVVM的主要目标是允许可测试的设计,模型层可以独立测试,模型中的所有类都可以轻松地遵循SRP.可以在不需要视图的情况下测试ViewModel; 在ViewModel中思考SRP变得更加棘手,但它肯定是可行的; 只记得打破你的课程,这样他们只有一个问题.View绑定了ViewModel,幸运的是,你对ViewModel的测试使得查看超级容易.请记住,您可以让每个View-let遵守SRP成为更大的集团View(容器)的一部分.

TL; DR?要直接回答您的问题,View是一组不会破坏SRP的类.因此,当ViewModel从View(s)(View-First)中抽象出来时,它们也是符合良好SRP的类的集合.


Gon*_*ing 6

我认为围绕MVVM的许多当前实践都违反了SPR(至少).这是另一种情况,简单地将控制器添加回MVVM将彻底解决所有问题.我称之为MVCVM :)

我们在所有最近项目中成功使用的模式是在模块中注册控制器,并在启动时初始化它们.控制器非常轻薄,是唯一需要在应用程序监听或发送消息的过程中闲逛的东西.在他们的初始化方法中,他们然后注册他们需要拥有的任何东西(视图和视图模型等).这种轻量级逻辑内存模式也可以实现更轻薄的应用程序(例如,WP7更好).

正如您所发现的那样,使用虚拟机的问题是,最终您遇到需要了解视图,命令或其他内容的情况,而不应该参与自尊的ViewModel!

我们遵循的基本规则是:

  • 控制器根据事件做出决策
  • 控制器获取数据并将其放入适当的View Model属性中
  • 控制器设置View Models的ICommand属性以拦截事件
  • 控制器显示视图(如果不在其他地方暗示)
  • 视图模型是"愚蠢的".绑定的保持数据,没有别的
  • 视图知道它们显示某种形状的数据,但不知道它来自何处

最后两点是你永远不应该打破的,或者关注点的分离会消失.

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

  • @Kit:ViewModels包含用于绑定命令事件的ICommand属性,但它们指向的操作(它们运行的​​代码)应由控制器确定/设置. (3认同)