基于MVVM模式开发Silverlight 3应用(理论篇)
一、引言
当前,Silverlight的正式版本为3.0,基于此技术的应用程序数量正在急剧增长。但是,到目前为止,Silverlight 3.0模板所支持的基本结构却意味着用户界面(UI)与其所需要的任何数据间是紧密集成的关系。虽然这种紧密集成的技术对于学习Silverlight本身来说是有益的,但是,当使用之来开发真实的应用程序时却会为测试、重构和维护等工作带来巨大的困难。
二、紧耦合设计带来的问题
在设计Silverlight应用程序时,我们所关心的核心问题是紧密耦合问题。造成这种紧密耦合的原因是:开发过程中,我们很容易把应用程序的各个层混合在一起。当一个层中拥有另一个层中所需要的大量信息时,说明你的应用程序正处于紧密耦合状态。我们不妨来考虑一个简单的Silverlight数据输入应用程序,假定此程序允许你查询某个城市的待售房屋信息。在一个紧密耦合的应用程序中,您可能会在用户界面中的一个按钮的Click事件处理程序中定义执行搜索的查询操作。于是,当规则改变或搜索语义发生变化时,无论是数据层还是用户界面层都必须进行相应的更新。
这种情况势必导致代码质量和编码复杂性的问题。每当数据层改变时,你必须进行同步更新并测试应用程序,以便确保所做的更改没有与发生的变化相违背。当一切都紧密地绑在一起时,在一个应用程序某一部分中的任何变化都可能会导致在代码的其他部位发生相应的变化。当你使用Silverlight开发简单的程序,例如一个电影播放器或菜单组件,紧密耦合的应用程序组件不太可能造成大的问题。但是,随着项目尺寸的不断增大,你会感觉到麻烦越来越多。
另一个问题是单元测试的问题。当一个应用程序是紧密耦合型的,你只能进行应用程序的功能(或用户界面)测试。同样,这对于一个小项目不是什么问题,但是随着项目规模和复杂性的不断增长,能够分层测试应用就变得非常重要。请记住,单元测试并不只是确保当在一个系统中使用它时此单元能够工作,而是需要确保它能够在一个系统中继续不断地使用。对系统各个局部进行单元测试可以保证,随着系统的变化,在这个过程中会更早期地发现问题,而不是和仅使用功能测试那样在最后才发现问题。因此,回归测试(例如,针对一个系统的每一个版本都进行单元测试)就变得至关重要—它可以确保系统中新增加的小变化不至于造成一系列的错误。
在程序开发过程中,定义不同的层可能会对一些程序员造成巨大的压力。但是,事实是:无论你是否考虑到基于分层思想构建程序,你都是工作在一个N层平台上,而且你的应用程序也都将分层工作。因此,如果设计之初缺乏正确的计划,你的应用程序最终将要么成为一个紧耦合的系统,要么充满了大量的硬编码,从而为以后的应用程序维护带来巨大的难题。
人们很容易以为建立一个有独立的层次的应用程序一定需要大量的基础设施才能使其良好地工作。但事实上,实现层之间的简单分离却是相当直接的事情。当然,你还可以通过使用控制反转等技术设计更复杂的应用程序分层,但这是要解决另外一些不同的问题—在本文中并不予以讨论。
三、以分层模式设计Silverlight应用程序
Silverlight程序并不要求你发明什么新东西,以便帮助你决定如何实现一个应用程序的分层设计。事实上,已经有一些众所周知的模式可以供你使用。人们很快会想到的一种模式是MVC(模型-视图-控制器)模式。在MVC模式中,模型是数据,视图是用户接口,控制器是位于视图、模型和用户输入之间的编程接口。但是,这种模式在类似WPF或Silverlight应用程序中实现声明式用户接口编程时效率并不高,因为这些技术所使用的XAML可能会在输入与视图之间定义某种接口(因为数据绑定、触发器和状态都可以以声明方式存在于XAML代码中)。
MVP(模型—视图—提供器)是另一个实现应用程序分层设计时常见的模式。在MVP设计模式中,提供器负责制定和管理视图的状态。像MVC模式一样,MVP模式也不太适合目前的Silverlight模型,因为XAML代码中可能包含声明式的数据绑定,触发器和状态管理。那么,这种模式带来我们怎样的启示呢?
另一方面,值得庆幸的是,WPF社团已经推出一种称为MVVM(模型-视图-视图模型)的模式。这种模式是对MVC与MVP模式的改进。在该模式中,视图模型部分为视图部分提供了一个数据模型和行为,但允许视图部分以声明方式绑定到视图模型上。于是,视图部分变成了一种XAML和C#的混合体(就像Silverlight控件一样),而模型部分描述了提供给应用程序的数据部分,由视图模型准备模型部分,以便把它绑定到视图部分。
在MVVM模式中,模型部分特别重要,因为它封装了对底层数据的访问—无论访问方式是通过一组Web服务,一个ADO.NET数据服务,或是一些其他形式的数据检索方案。该模型部分与视图模式是相分离的,从而使视图的数据(即视图模型部分)能够独立于实际数据进行测试。图1展示了一个MVVM模式的例子。
图1. Model-View-ViewModel模式示意图
四、构建示例方案
在简单地总结了流行的应用开发模式之后,为了帮助您更具体地理解MVVM模式的实现方案,我们来分析一个简单的Silverlight 3应用示例。当然,这个例子未必反映了实际的情形,仅用于说明这一模式。这个例子由五个不同的项目组成,共同存在于一个Visual Studio解决方案中。(尽管你不需要针对每一个单独的项目创建一个单独的层,但是这样做却往往是一个不错的选择。)请注意,这个例子把整个解决方案进一步分离到两个文件夹中,即Client文件夹和Server文件夹。
其中,在Server文件夹中有两个项目:一个ASP.NET Web应用程序(MVVMExample),它将负责承载我们的Silverlight项目和有关服务;另一个是一个.NET类库项目,它包含了数据模型部分。
在Client文件夹中有三个项目:一个Silverlight项目(MVVM.Client),用于实现我们的应用程序的主用户界面;一个Silverlight客户端库(MVVM.Client.Data),其中包含了模型部分和视图模型部分,还有服务引用;最后一个是Silverlight项目(MVVM.Client.Tests),其中包含了单元测试内容。从图2中你可以观察到这种拆开来的项目布局。
图2. 示例程序项目布局图
在本例中,在服务器端构建上,我使用的技术有:ASP.NET,Entity Framework(实体框架)和一个ADO.NET数据服务。从本质上看,我在服务器端创建了一个简单的数据模型,而且选择基于REST的服务方式来对外提供这种数据模型的使用。篇幅所限,有关ADO.NET数据服务的细节讨论,在此略过。
五、小结