MVC
随着面向对象的语言(如Java)的迅速发展和普及,越来越多的编程人员开始在应用开发中使用这些语言。然而原有的开发语言(即面向操作的开发语言如C++等)在短时间内还不可能退出历史舞台,因此现在就出现了面向对象的语言和传统的面向操作的语言共存的局面。在设计应用中同时使用两类不同的语言(混合语言设计)比过去只使用一类语言会带来许多新的问题,其中复杂性就是混合语言设计中最经常遇到的问题。下面我们探讨混合语言设计中可能导致复杂性增加的地方,以及如何减少以至消除这些复杂性。
复杂性
复杂性是应用开发过程中最令人头疼的一个问题。每当在一个应用中增加一个功能时,它的复杂性通常呈几何级的增长。这种复杂性往往导致程序的开发无法再继续下去。这也是现在为什么许多应用只有Beta版本而没有正式版的原因。
专家将应用开发过程产生的复杂性分为两类,即非本质的(accidental)和本质的(essential)。本质的复杂性是对于解决目标问题所必然产生的复杂性,非本质的复杂性是由于选择了不适当的开发工具和设计工具而产生的复杂性。对于一个功能确定的程序来讲,本质的复杂性是确定的,而非本质的复杂性则是没有限制的。因此,一个应用的开发要想较顺利地取得成功,就需要尽可能地减少非本质的复杂性。
OOD的特点
面向对象的设计(OOD)将一个程序分解成根据具体的对象而设计的一系列元素。这些具体对象的行为和数据以一种叫做“类(class)”的编程单元进行打包。应用程序创建一个或多个这些类的例示,也称为“对象(object)”。类的行为是通过创建对象之间的关系组合在一起的。
OOD允许开发者用两种主要的方法来控制复杂性的增加。第一,OOD定义严格的出口语义,这允许开发者隐藏实现的细节,并且明确说明什么方法是其它的对象可以访问的。这个信息隐藏使得可以对大部分的代码进行修改而不影响其它的对象。
第二,OOD将对象之间的关系分为四类:继承、包容、使用和协调。适当地使用这些关系可以大大减少应用开发过程中本质的和非本质的复杂性。如,继承是产生面向对象设计中可再使用的主要因素。这个再使用性是通过代码共享和多态性获得的。这种再使用可以大大减少应用的本质的复杂性。包容允许一个类的用户在使用包容器时忽略被包容的类(class)。这个简化使设计者能够大大减少应用的非本质的复杂性。
可视化接口在OOD方面的不足
许多程序都需要可视化接口,这些接口由对话框、选单、工具条等组成。这些可视化接口的增加会引进OOD设计的不足,使得一个好的面向对象的设计走向反面。可视化接口有三个属性可能会给应用开发带来麻烦。
第一,可视化接口提高了传统的面向操作的拓扑结构。用户产生接口事件,如开关按键和列表框选择等,受到程序的一个模块的驱动并且用来对静态的数据进行操作。在设计中将这面向操作的拓扑结构同一个面向对象的设计混合在一起将导致对象之间的大量的杂合。
第二,用户接口通常对于同样的信息经常会需要许多不同的显示。如,一个客户选择列表框可以包含一个客户的名字和电话号码以及许多其它客户的名字。
当用户选择某个特定的客户后,他/她的名字和电话号码及其它全部相关的信息都会详细地显示出来。
除此之外,一个简单的程序可能具有不同的用户接口。如一个银行账户系统有一个接口用于出纳员来访问账户平衡、存款和取款,而监督者的接口则包含另外的信息并加上账号管理的功能。这些不同的接口很容易导致类的扩展。
最后,可视化接口在整个设计阶段还会进行较大的改变。这些改变包括完全重新安排用户与系统的交互操作等。可视化接口的这些改变即使在最好的设计中也会增加应用开发的复杂性。
MVC弥补可视化接口/OOD的不足
模型/界面/控制器(Model/View/Controller,MVC)编程技术允许一个开发者将一个可视化接口连接到一个面向对象的设计中,而同时还可以避免我们上面讨论的几个问题。MVC最初是为Smalltalk语言而设计的。MVC通过创建下面三个层将面向对象的设计与可视化接口分开:
模型(Model):模型包含完成任务所需要的所有的行为和数据。模型一般由许多类组成并且使用面向对象的技术来创建满足五个设计目标的程序。
界面(View):一个界面就是一个程序的可视化元素,如对话框、选单、工具条等。界面显示从模型中提供的数据,它并不控制数据或提供除显示外的其它行为。一个单一的程序或模型一般有两种界面行为。
控制器(Controller):控制器将模型映射到界面中。控制器处理用户的输入,每个界面有一个控制器。它是一个接收用户输入、创建或修改适当的模型对象并且将修改在界面中体现出来的状态机。控制器在需要时还负责创建其它的界面和控制器。
控制器一直决定哪些界面和模型组件应该在某个给定的时刻是活动的,它一直负责接收和处理用户的输入,来自用户输入的任何变化都被从控制器送到模型。
界面从模型内的对象中显示数据。这些对象的改变可以通过也可以不通过用户的交互操作来完成。如:在一个Web浏览器中负责接收页面的对象收集和装配栈中的信息,必须有某种方式来让这些对象通知界面数据已经被改变了。在模型变化时有两种方法来对界面进行更新。
在第一种方法中,界面可以告诉模型它正在监视哪些对象。当这些对象中有任何一个发生变化时,一个信息就被发送给界面。界面接收这些信息并且相应地进行更新。为了避免我们上面讨论的不足,模型必须能够不用修改就支持许多种不同的界面显示。
第二个方法并不直接将界面连接到模型中,它的控制器负责在模型变化时更新界面。控制器通过对模型对象或观察器方法进行监测来检测模型中的变化。这个方法不用了解界面的模型知识,因此界面就变成是可以跨应用使用的。
使用MVC的优点
MVC通过以下三种方式消除与用户接口和面向对象的设计有关的绝大部分困难:
第一,控制器通过一个状态机跟踪和处理面向操作的用户事件。这允许控制器在必要时创建和破坏来自模型的对象,并且将面向操作的拓扑结构与面向对象的设计隔离开来。这个隔离有助于防止面向对象的设计走向反面。
第二,MVC将用户接口与面向对象的模型分开。这允许同样的模型不用修改就可使用许多不同的界面显示方式。除此之外,如果模型更新由控制器完成,那么界面就可以跨应用再使用。
最后,MVC允许应用的用户接口进行大的变化而不影响模型。每个用户接口的变化将只需要对控制器进行修改,但是既然控制器包含很少的实际行为,它是很容易修改的。
面向对象的设计人员在将一个可视化接口添加到一个面向对象的设计中时必须非常小心,因为可视化接口的面向操作的拓扑结构可以大大增加设计的复杂性。
MVC设计允许一个开发者将一个好的面向对象的设计与用户接口隔离开来,允许在同样的模型中容易地使用多个接口,并且允许在实现阶段对接口作大的修改而不需要对相应的模型进行修改。