MVVM违反干吗?
看来,我做的ViewModels 像其他类似的可疑 ,他们似乎需要大量的代码重复,例如在我有一个当前的项目:
- SmartForm :表示要填写的数据表单的模型 ,具有以下属性:
- IDCODE
- 标题
- 描述
- SmartFormFields的集合
- 等等
- SmartFormControlView 视图
- SmartFormControlViewModel ViewModel
- IDCODE
- 标题
- 描述
- SmartFormFields的集合
- 等等
所以我的ViewModel基本上和我的Model一样 ,只是用了所有的OnPropertyChangedfunction来绑定View。
看来,我重构和扩展了这一点,我对我的模型做的每一个小的改变,我必须做一个 镜像改变的ViewModel 。
这似乎违反了模式的基本规则不要重复自己 。
我是不是正确地实现了MVVM模式,还是MVVM的一个固有特性,那就是Model和ViewModel之间总会有一对一的重复?
我个人认为它不会违反DRY,因为模型和视图模型(我更喜欢术语演示者)并不指向相同的信息。 例如,你的虚拟机和M都有一个Title属性,但是你的虚拟机的Title属性也可以包含validation,而你的模型的Title属性可以假设有效性。
虽然虚拟机可能包含模型的所有属性,但也有可能进行validation(例如,标题必须是非空白的),数据依赖性,可绑定的UI特定属性(图标,颜色,画笔,等等),这些不是视图的一部分。
基本上所有的用户界面模式都有类似的“重复”的方式,即级联修改。 尝试在MVC中更改模型而不更改控制器。
这就是说,MVVM(或任何用于分离UI,逻辑和状态的UI模式)对于简单情况(如您的示例)可能过于乏味。 当逻辑变得比状态传递稍微多一些时,分离控制器/演示者/视图模型的值就会减小。
在你的具体情况下,如果你的虚拟机没有任何逻辑,validation或UI特有的属性,你的模型不需要被持久化,序列化或者向后兼容现有的结构或者在虚拟机中添加这样的逻辑是微不足道的),我会强烈考虑将M和VM结合起来,以避免创build其唯一目的是获取/设置底层模型属性的属性。
一个简单的解决scheme是有一个抽象的ViewModel(VM)基类来公开这个模型。 您可以在有意义的场景中select此虚拟机。
即
public abstract class ViewModelBase<T> { public T Model { get; set; } }
如果你的模型有INotifyPropertyChanged实现你的视图将得到事件。 这样做是让您的视图访问您的模型中的每个属性,这是不是你想要的一些东西。
你也可以像这样使用属性初始值设定项(我个人已经存储在代码片段中):
public abstract class SampleViewModel { public int MyProperty { get { return Model.MyProperty; } set { Model.MyProperty = value; OnPropertyChanged("MyProperty"); } } }
在大多数情况下,你认为将是对你的虚拟机进行更改的人,当它的任何绑定到该属性的控制将被告知发生了什么事情。
希望有所帮助。
这是一个有趣的说法……实际上,通常需要修改ViewModel以反映模型中的更改。
这将是很好,如果它可以是自动的…实际上我认为这可能是可能的,通过在ViewModel中实现ICustomTypeDescriptor:GetProperties将通过reflection返回模型的所有属性。 然而,我不确定这是否合理,因为模型可能不包含属性:它可能是方法,字段或任何东西,并不是模型中的所有东西都可以在ViewModel中使用。
有一件事似乎在这里错过了,而且你的简单化的例子并没有公开,事实上你的Views通常会聚合包含在多个Domain Modeltypes中的数据。 在这种情况下,您的ViewModels将包含对多个领域模型(不同types)的引用,从而汇总一组特定视图可能希望公开的相关数据。
其他人则对MVC / MVVM模式组件的angular色提供了很好的评论。 无论您select哪种模式,我都想提供一个解释重复性的基本观察。
通常在你的数据层,业务层和UI层之间会有某种重复。 毕竟,一般来说,您必须向最终用户(UI) 显示每个属性,对其行为(业务层)进行build模并保留该值(数据层)。
正如其他人所指出的那样,每一层的财产可能会有所不同,这就解释了一些重复的基本需要。
当在足够大的系统上工作的时候(或者在有合适团队的小项目上),我倾向于用UML来build立这种types的信息,并且使用代码生成(通常与部分类相结合)来处理重复的方面。 作为一个简单的例子,Last Name属性可能会有一个要求(在我的UML模型中),它将数据限制为50个字符。 我可以生成代码来强制执行这个限制到我的用户界面层(例如通过物理限制input),生成代码到我的业务层重新检查限制(“永远不信任用户界面”),可能抛出一个exception如果数据太长,并生成我的持久层(如NVARCHAR(50)列,适当的ORM映射文件等)。
2012更新
微软的数据注释及其在UI层(例如ASP.Net MVC )和数据层( entity framework )中的支持对于实现我以前生成的代码所关注的许多问题有很大的帮助。
埃里克·埃文斯(Eric Evans)在他的着作“域驱动devise”一书中提到,模型重构不应该太难,概念的改变不应该跨越太多的模块,否则重构模型会变得不可行,所以,如果你问我,模型的“复制”在ViewModel中的sorting当然很难模型重构。
Eric提到,模型的凝聚力和隔离度应该更加重视,而不是基于技术关注(数据库访问,POCOS,表示)来分层。 最重要的问题是,领域模型是业务领域的一个很好的代表,因此它对于领域模型是在一个孤立的层中是最重要的,而不是跨越几个模块,以便它很容易更新(重构)。
考虑到刚才所说的,我将在ViewModel中使用相同的Model对象,如果我想降低对Model对象的“访问”级别,那么我会“传递”一个对由模型对象。 例如:
// The primary Model classes public partial class OrderItem { public int Id { get; } public int Quantity { get; set; } public Product Item { get; set; } public int Total { get; set; } public void ApplyDiscount(Coupon coupon) { // implementation here } } public partial class Product { public int Id { get; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } } // The shared views of those model classes public partial class OrderItem : IOrderItemDTO { public IProductDTO Item { get { return this.product; } } } public partial class Product : IProductDTO { } // Separate interfaces... // You enforce the rules about how the model can be // used in the View-ViewModel, without having to rewrite // all the setters and getters. public interface IOrderItemDTO { int Id { get; } int Quantity { get; set; } IProductDTO Item { get; } int Total { get; } } public interface IProductDTO { string Name { get; } string Description { get; } decimal Price { get; } } // The viewmodel... public class OrderItemViewModel { IOrderItemDTO Model { get; set; } }
我只知道MVC,而在MVC中,包含GUI的Model-Class是一些错误。 SmartForm似乎是一个表单,这意味着它不是一个模型。 我不知道你在编程什么,但我给你一个模型的例子:
拿一个日历。 你可以问class级今天是几号,每月几号,每个月有多less天,……但是没有图示。 视图(CalenderViewMonth或whater你想要)在屏幕上打印一个月。 它知道一个日历,并问他在不同的单元格写什么。
本质上 – 你可能在MVVM的build模/理解方面有些问题(这是一个现代的MVC的.NET变体)。
编辑:
我只是在Wikipedia上查找MVVM。 模型就像MVC中的模型一样。 像MVC中的视图一样 – 只有graphics表示。 ViewModel是通用视图和专用模型之间的胶水。 某种适配器。 不应该违反DRY。
我认为是的,香草MVVM确实违反了DRY。 但是我已经开始了很多情况下可以解决这个问题的PDX库 。 我写了这个post ,我相信这个问题。
基本上,我的目标(其中之一)是让Viewmodels不用担心UI通知。 PDX项目还处于起步阶段,但是如果你正在阅读这个问题,你可能会觉得它很有用,如果你有任何反馈,我将不胜感激。