关于MVP和MVVM的一些困惑
在提出这个问题之前,我已经阅读了一篇关于MVP和MVVM的文章。 (例如:http://martinfowler.com/eaaDev/uiArchs.html)
但是在开始富客户端应用程序开发时,我仍然对这两种模式感到困惑。
例如,富客户端应用程序将同时使用本地数据库和远程服务。
在业务层中,有两种对象!
从我的本地数据库读取的域对象。
用于保持持久连接的会话对象(例如:异步观看在线用户)
Domain对象是正确的Model,但我是否需要一个特殊的模型层来管理在线用户(或char消息),然后映射到ViewModel?或者直接将这些数据设置为ViewModel? (映射是否冗余?由于一个ViewModel可以有多个视图,因此ViewModel与Model非常相似)
例如,想象一下聊天应用程序,即使您在离线环境中打开应用程序,您仍然可以在聊天窗口中看到最近的消息。
但是这些最近的消息是在ViewModel中,我们应该将ViewModel持久化到数据库吗? (它们恰好是Model或ViewModel?)
在MVP中,只有一个"模型层",因此我可以在此模型层中管理和存储domian对象和会话对象。所有视图特殊状态都在视图中,不会被持久化。 Presenter将控制视图状态并在Model和View之间同步数据。
在MVVM中,有两个"模型层" (Model和ViewModel),视图状态和Model的副本都存储在ViewModel中。那么模型的副本是多余的?
或者只是将外部服务调用放在单独的模型层中?
非常感谢: - )
答案 0 :(得分:1)
MVC最初将模型定义为" digital model that exists in the computer"而不是人类用户的心理模型"。因此,这是一个非常模糊的概念,可以涵盖你想要的任何现实,尽管自那以后出现的无数MV *实现引入了更多自以为是的定义。
思想流派中的传统冲突是MVC / P中的模型是应该是域对象还是仅仅反映了向用户呈现的内容。 MVVM给出了明确的答案(见2.和3.)
不,因为ViewModel只是一个瞬态内存结构,代表屏幕上显示的内容。如果MV *模式中有任何内容存在,那就是模型。
MVVM的存在是为了将业务模型(M)与UI屏幕(VM)的数据和行为分开,这是MVP没有明确说明的区别。在MVVM中没有两个模型副本,M和VM不是多余的,因为他们总是拥有相同的数据而他们从不拥有相同的行为。
例如,UserCredentials
模型对象将包含登录名和密码字段,而相应的UserCredentialsViewModel
可能包含额外的ConfirmPassword字段和VerifyPasswordMatchesConfirm()
方法,因为这是什么显示给用户。
另一个主要区别是存在基于事件的数据绑定 在MVVM中,它不存在于MVP中。一个结果是你经常 请参阅客户端上使用的MVVM模式 技术允许这样的绑定(Javascript,WPF)而MVP是 主要用于服务器端(主要是ASP.NET)。 MVP并不比MVVM好,它们只适合不同的生态系统。
Presenter和ViewModel就像他们的名字所暗示的那样,是UI野兽。他们可能会看到DTO通过远程服务呼叫产生的DTO,但他们不应该呼叫远程服务,因为它&#39&#39> ;这不是演示对象的责任。您应该在单独的基础架构服务中执行此操作。
答案 1 :(得分:0)
在所有这些情况下,我都不会将这些MV *模式的任何字母视为图层。将它们视为分离的问题。
要做好任何MV *模式,我建议您在模型和视图模型之间进行映射。主要是因为您的模型关注的是在您的业务领域的上下文中表示该实体,因为您的视图模型的关注点是将相关信息从一个或多个模型显示/转换到视图上。如果您将这些看作是一对一的关系,或者您遇到任何试图直接在View中使用模型的人,那么他们做错了。特别是如果模型是通过类似ORM(EF / NHibernate)的方式从数据库派生的。在最糟糕的情况下,人们不使用映射并在他们的视图中使用他们的ORM生成的实体(即使他们试图通过使用代码优先来自欺欺人)。理想情况下,这些层应该能够独立改变。
回答你的问题:
答案 2 :(得分:0)
这是我的0.02美元:
1)'模型'是一个抽象概念。对我来说,模型是完成工作所需的一切。例如,在MVP中,Presenter可能依赖于其视图和两个服务。这里,两个服务代表模型。在另一种情况下,它可能是单个存储库,也可能只是数据库连接。
2)不应该保留ViewModel。 ViewModel将通过Model与可持久的东西进行交互。
3)请参阅我对此question的回答。这不是一个更好的问题。这是一个关于哪个工具适合这项工作的问题。
4)我认为Presenter / ViewModels可以使用域对象。
我更喜欢通过使用原语来保护Views免受域对象的了解,但这只是一种偏好。