为什么要使用MVVM?
好的,我一直在研究MVVM模式,每次我以前都试过,我放弃了很多原因:
- 不必要的超长编码
- 编码器没有明显的优势(我的办公室没有devise师,目前只有我自己很快成为另一个编码器)
- 没有很多资源/好的做法的文件! (或者至less很难find)
- 不能想到这是有利的一个场景。
我即将再次放弃,并想我会问是否有人回答上述原因。
我真的不能看到使用这个单一/合作伙伴编码的优势。 即使在10个窗口的复杂项目。 对我来说,DataSet是一个足够好的观点和约束在布伦特回答下面的问题
可以有人展示一个例子,与XAML DataBinding相比,使用MVVM模式会节省多less时间。
我的绑定的100%目前在XAML中完成。 因此,我不认为虚拟机的重点是它需要编写和依赖的额外代码。
编辑:
经过下午的关于MVVM的研究,我终于find了一些让我从这个答案中体会到真正的好处。
概要
- 所有模式的使用都是情境的,而好处(如果有的话)总是在于降低复杂性。
- MVVM指导我们如何在GUI应用程序中的类之间分配职责。
- ViewModel将模型中的数据投影到适合View的格式。
- 对于微不足道的项目,MVVM是不必要的。 只使用视图就足够了。
- 对于简单的项目,ViewModel / Model拆分可能是不必要的,只需使用Model和View就足够了。
- Model和ViewModel不需要从一开始就存在,可以在需要的时候引入。
何时使用模式以及何时避免使用模式
对于一个足够简单的应用程序,每个devise模式都是过度的。 假设你编写一个GUI应用程序,显示一个button,当按下时显示“Hello world”。 在这种情况下,像MVC,MVP,MVVM这样的devise模式都会增加很多复杂性,而不会增加任何价值。
总的来说,引入devise模式只是因为它有点适合,总是一个不好的决定。 应该使用devise模式来降低复杂性,或者直接降低整体复杂性,或者用熟悉的复杂性来代替不熟悉的复杂性。 如果devise模式不能降低这两种方法的复杂性,请不要使用它。
为了解释熟悉和陌生的复杂性,请采取以下2个字符序列:
- “D.€|?重新%DFA C”
- “CorrectHorseBatteryStaple”
虽然第二个字符序列是第一个序列长度的两倍,但它比第一个序列更容易阅读,写得更快,并且更容易记忆,因为它比较熟悉。 代码中熟悉的模式也是如此。
请注意,将来所有将要使用代码的开发人员都可能不熟悉某些模式。 就前面的例子而言,取决于记住它的人的经验和训练,以下顺序可能比也可能不易于记忆:“3.14159265358979323846264338327950”。 在一些涉及更高级devise模式的情况下,如果维护开发人员已经熟悉这种devise模式,那么只使用devise模式是有意义的。
MVVM
也就是说,让我们通过一个例子来深入MVVM的话题。 MVVM指导我们如何在GUI应用程序中的类之间(或之间的更多关于这个)分配责任,目标是拥有less量的类,同时保持每个类的责任数量小,定义明确。
“适当的”MVVM至less假设一个适度复杂的应用程序,它处理从“某处”获得的数据。 它可能从数据库,文件,Web服务或其他各种来源获取数据。
例
在我们的例子中,我们有2个类View
和Model
,但没有ViewModel
。 Model
包装了一个csv文件,它在启动时读取,并在应用程序closures时进行保存,用户对数据进行的所有更改都会进行。 View
是一个Window类,它将Model
中的数据显示在表格中,并让用户编辑数据。 csv的内容可能看起来像这样:
ID, Name, Price 1, Stick, 5$ 2, Big Box, 10$ 3, Wheel, 20$ 4, Bottle, 3$
新要求:以欧元显示价格
现在我们被要求改变我们的应用程序。 数据由一个二维网格组成,该网格已经有一个“价格”列,其中包含一个以美元为单位的价格。 我们需要添加一个新的列,以预先确定的汇率为基础,以美元为单位显示欧元的价格。 csv文件的格式不能改变,因为其他应用程序使用相同的文件,而这些其他应用程序不在我们的控制之下。
一个可能的解决scheme是简单地将新列添加到Model
类。 这不是最好的解决scheme,因为Model
保存了所有暴露给csv的数据 – 我们不希望在csv中有新的欧元价格列。 因此,对Model
的改变将是不平凡的,而且也很难描述Model类所做的,这是一种代码味道 。
我们也可以在View
进行更改,但是我们当前的应用程序使用数据绑定来直接显示由Model
类提供的数据。 由于我们的GUI框架不允许我们在表中绑定到数据源时在表中引入额外的计算列,因此我们需要对View
进行重大更改才能使其工作,从而使View
更复杂。
介绍ViewModel
在应用程序中没有ViewModel
,因为到目前为止, Model
都是以Csv所需的方式呈现数据,这也是View
所需要的。 之间有一个ViewModel
会增加复杂性没有目的。 但现在Model
不再以View
的方式呈现数据,我们编写一个ViewModel
。 ViewModel
以这样的方式ViewModel
的数据,使View
可以变得简单。 以前, View
类订阅了Model
类。 现在,新的ViewModel
类订阅了Model
类,并将Model
的数据公开到View
,并以额外的一列显示了以欧元表示的价格。 View
不再知道Model
,它现在只知道ViewModel
,从View
的angular度来看,它看起来和Model
之前做的一样 – 除了公开的数据包含一个新的只读列。
新的要求:格式化数据的不同方式
客户的下一个要求就是我们不应该将数据显示为表格中的行,而是将每个项目(又名行)的信息显示为卡片/盒子,并在屏幕上以4×5的格子显示20个盒子,显示20一次一盒。 因为我们保持View
的逻辑简单,所以我们只需要用一个新的类来完全替代View
。 当然还有另外一个客户喜欢旧的View
,所以我们现在需要支持这两个。 因为所有常见的业务逻辑已经发生在ViewModel
,这并不是一个问题。 所以我们可以通过将View类重命名为TableView
,然后编写一个新的CardView
类来显示卡片格式的数据。 我们还必须编写一些胶水代码,这可能是启动函数中的一个oneliner。
新要求:dynamic汇率
下一个客户的要求是我们从互联网上取得汇率,而不是使用预定的汇率。 这是我们重新审视我之前关于“图层”的陈述的一点。 我们不改变我们的Model
类来提供汇率。 相反,我们写(或find)提供汇率的完全独立的附加类。 这个新类成为模型层的一部分,我们的ViewModel
合并了csv-Model和Exchange-rate-Model的信息,然后将它呈现给View
。 对于这个改变,旧的Model类和View类甚至不必被触及。 那么,我们确实需要将Model类重命名为CsvModel
然后调用新的类ExchangeRateModel
。
如果我们之前没有引入ViewModel,而是等到现在才这么做的话,现在介绍ViewModel的工作量会更高,因为我们需要从View
和Model
删除大量的function并将function移到ViewModel
。
unit testing后记
MVVM的主要目的不是Model和ViewModel中的代码可以放在Unit Test下。 MVVM的主要目的是将代码分解成具有less量明确职责的类。 使代码由less量明确定义的职责组成的代码的好处之一就是将代码放在unit testing下更容易。 一个更大的好处是代码更容易理解,维护和修改。
实施模式和遵循最佳实践常常觉得毫无意义的追求,但当老板要求您添加或调整function的几个月后,您将成为一个转换。 使用MVVM(以及一般的模式),您实际上可以遵循自己的代码,并在几个小时或几天内完成要求,而不是几周或几个月。 (这个改变很可能只是几行代码,而不是花几个星期的时间来试图弄清楚你在做什么之前先做了什么,甚至在尝试添加新的function之前。
跟进:模式和最佳实践实际上会减缓最初的开发速度,而这对pipe理层和工程师来说常常是一种难以推销的做法。 投资回报(投资回报率)来自具有良好结构的代码,这些代码实际上是可维护的,可扩展的和可扩展的。
举个例子,如果你正确地使用MVVM,你应该能够对显示逻辑做出非常大的改变,比如换出一个完整的视图,而不会影响数据和biz逻辑。
一个关于在你的模型中使用数据集的思考(实际上我也是这么做的)。数据集似乎是在应用程序中移动模型数据的完美方法。 问题来自您如何识别数据项目。 由于数据存储在行和列中,因此必须按列名称或索引执行查找,并且必须筛选特定的行。 这些逻辑意味着必须在应用程序的布线逻辑中使用魔术string和数字。 使用types化的数据集可以缓解这个问题,但不是完全的。 使用types化的数据集,您将会从MVVM转移到UI和数据源之间更紧密的耦合。
它可以帮助您分离GUI和程序逻辑; 把它们混合在一起会导致很难维护应用程序,特别是当你的项目随着时间的推移而增长时。
从这里 :
作为开发人员,为什么要关心Model-View-ViewModel模式呢? 这个模式给WPF和Silverlight开发带来了许多好处。 在你继续之前,问问自己:
- 您是否需要与devise师共享一个项目,并且具有devise工作和开发工作几乎同时发生的灵活性?
- 你需要彻底的unit testing你的解决scheme吗?
- 您的组织内部和跨项目是否有可重用的组件?
- 您是否希望更灵活地更改用户界面,而不必重构代码库中的其他逻辑?
如果对这些问题中的任何一个回答“是”,这些只是使用MVVM模型可以为您的项目带来的一些好处。
- 与devise师(不是程序员,只是使用Blend的人)
- 代码是可testing的(unit testing)
- 在不改变其他代码的情况下更改视图要容易得多
- 在开发UI时,你可以模拟模型并开发你的界面,而不需要运行真正的服务(仅仅使用模型中的模拟数据)。 然后,您只需翻转标志并连接到服务。
关于MVVM有很多好的东西,但最重要的是能够testing你的代码(unit testingViewModels)。
视图和视图模型之间缺乏连接确实有助于松耦合。 重新使用你编码的组件变得非常简单。
从Josh Smith的关于MVVM的文章 :
除了使MVVM成为构build应用程序的自然方式的WPF(和Silverlight 2)function之外,该模式也很受欢迎,因为ViewModel类易于进行unit testing。 当应用程序的交互逻辑存在于一组ViewModel类中时,您可以轻松编写testing它的代码。 从某种意义上说,视图和unit testing只是两种不同types的ViewModel消费者。 为应用程序的ViewModel提供一套testing,可以提供免费,快速的回归testing,这有助于降低维护应用程序的成本。
对我而言,这是使用MVVM最重要的原因。
之前,我会控制哪些将视图和视图模型混合在一起。 但是一个视图本质上具有鼠标和键盘事件作为input,并将绘制像素作为输出。 你如何testing类似的东西? MVVM使得这个问题消失了,因为它将不可testing的视图与可testing的视图模型分开,并使视图层尽可能地薄。
在本文中阅读MVVM的介绍
在2005年,目前微软WPF和Silverlight架构师之一的John Gossman在他的博客上发布了Model-View-ViewModel(MVVM)模式。 MVVM与Fowler的Presentation Model完全相同,因为两种模式都具有View的抽象,它包含View的状态和行为。 Fowler引入了Presentation Model作为创build一个View的UI平台无关抽象的手段,而Gossman则将MVVM作为一种标准化的方式来利用WPF的核心特性来简化用户界面的创build。 从这个意义上讲,我认为MVVM是专门针对WPF和Silverlight平台定制的更一般的PM模式。
..
与MVP中的Presenter不同,ViewModel不需要对视图的引用。 该视图绑定到ViewModel上的属性,而ViewModel反过来暴露模型对象中包含的数据以及特定于该视图的其他状态。 view和ViewModel之间的绑定很容易构造,因为ViewModel对象被设置为视图的DataContext。 如果ViewModel中的属性值发生更改,则这些新值将通过数据绑定自动传播到视图。 当用户单击视图中的button时,ViewModel上的命令将执行以执行请求的操作。 ViewModel,从来不是视图,执行对模型数据的所有修改。 视图类不知道模型类存在,而ViewModel和模型不知道视图。 事实上,这个模型完全没有意识到ViewModel和view存在的事实。 这是一个非常松散耦合的devise,它将以多种方式支付股息,正如您将很快看到的那样。
另外文章解释了为什么要使用这些GUI模式:
在一个简单的“你好,世界!”中使用devise模式是没有必要和适得其反的。 程序。 任何有能力的开发人员都能一眼就看懂几行代码。 然而,随着程序中特征的数量增加,代码和移动部分的行数相应地增加。 最终,一个系统的复杂性和它所包含的反复出现的问题,鼓励开发人员以更容易理解,讨论,扩展和排除故障的方式组织他们的代码。 我们通过在源代码中的特定实体上应用知名的名称来减less复杂系统的认知混乱。 我们通过考虑其在系统中的functionangular色来确定应用于一段代码的名称。
开发人员通常会根据devise模式有意地构build代码,而不是让模式有机地出现。 这两种方法都没有错,但在本文中,我将检查明确使用MVVM作为WPF应用程序的体系结构的好处。 某些类的名称包含MVVM模式中的众所周知的术语,如类是视图的抽象,则以“ViewModel”结尾。 这种方法有助于避免前面提到的认知混乱。 相反,你可以愉快地存在于一个混乱的状态中,这是大多数专业软件开发项目的自然状态!
我仍然自己来抓住这个模式,但我认为这是有价值的。 现在最大的挑战就是这个方法还是比较新的,所以存在很多混乱,模式的某些关键组成部分仍然尴尬。 我发现了一些帮助我做出更清晰的模式实现的东西:
-
我大量使用Josh Smith MVVM基金会的RelayCommand。 这使得通过命令从View到ViewModel的绑定更加清晰。
-
我使用AOP来缓解实施INotifyPropertyChanged的痛苦。 我目前正在使用Postsharp,但我相信有其他工具可以做到这一点。 如果我没有发现这一点,我可能已经放弃了,因为手工实现它的样板代码真的让我烦恼。
-
我不得不颠倒我的方法来实现软件。 我们的软件不再像一个独裁者那样告诉他们所有的仆从要做什么,而是使用他们的仆从,我的软件变得更加松散耦合的服务问题:
-
这是我知道该怎么做的
-
这些是我需要做的事情
-
当你以这种方式开始构build你的代码,并使用可以方便地连接依赖关系的工具(有很多IoC框架可供select),我发现它简化了MVVM的一些尴尬,您可以减less与将模型注入到ViewModels相关联的样板代码,并findViewModel使用的各种View Services(如显示文件对话框)。
学习这种不同的方法是一项巨大的投资,如同实施方面的任何重大转变一样,当你第一次使用它时,生产力要低得多。 但是,我已经开始看到隧道尽头的一些亮点,我相信,一旦我掌握了杂乱的细节,我的应用程序将变得更清洁,更易于维护。
为了通过Postsharp来解决关于INotifyPropertyChanged的问题,我使用了一个基于这个例子的方面。 我已经为我的使用定制了一些,但是这给了你的要点。 有了这个,我只是标记类NotifyPropertyChanged,所有的公共属性将在他们的setter中实现模式(即使它们是自动属性设置器)。 这让我感觉更清洁,因为我不必担心是否要花时间让类实现INotifyPropertyChanged。 我可以添加属性,并完成它。
我同意使用MVVM通过编写矿石代码给我们更多的权重,但是看看一切都是孤立的光明的一面,如果你是一个devise师,所以你可以devise你的程序,其他人可以为你编码和其他的数据库层,如果你不使用MVVM,看看在大型企业应用程序中如何保持可维护的环境,那么维护几乎是在杀死….我自己在开发ERP解决scheme时使用它,维护是非常直接的,因为的隔离级别
从长远来看,如果因为其他人发布的所有原因而使用像MVVM这样的模式,您将会感到高兴。 请记住,您不需要逐字地遵循模式要求,只要确保您的窗口(视图)和您的逻辑(代码隐藏)之间有良好的分离。
MVVM的好处
- 降低复杂性。
- 隔离devise和开发。
- dependency injection。
- 主要优点是当你有一个MVVM结构化的Windows Phone应用程序,并且希望为Windows Metro Desktop开发相同的function时,只需要关注devise,因为可以使用相同的视图模型。
希望它有帮助。