用户界面和业务模块的互动方式,在程序设计中经常采用MVC模式。MVC模式并不是一个特别的模式,而是一些特定模式的组合。基本上包括三个对象:业务模块(Model)、用户界面(View)和控制器(Controller),关系如下:
现在开发应用程序经常使用一些所见即所得的开发环境,使得用户界面的制作非常方便。然而,用户界面是最容易发生需求变更的部分,用户界面发生变化,经常对业务模块产生影响。并且,用户界面是不利于自动测试的。一旦某些代码依赖用户界面,这样的代码就很难在别的模块中调用了,因此业务逻辑不能在界面层次中进行,否则会造成不能复用,不能复用自然会增加复制粘贴的代码,造成错误的扩散,放大需求变更的影响。所以应该尽量做到用户界面和底层的业务模型分离。
在具体的环境下,这些因素可能发生一些变化。在windows窗体程序中,控制器和界面经常是合并在一起的,比如MFC框架中使用的Document-View模式,其中的Document对应MVC中的Model,负责保存业务数据,处理业务逻辑,View相当于MVC中的View+Controller,负责用户界面的显示、用户输入的收集和画面的跳转控制。
好的设计和坏的设计有时候需要写的代码是一样多的,但是这些代码放的位置不一样。MVC中最重要的一点就是清楚Controller应该处于什么样的地位,应该完成什么样的功能。下面用一个web应用程序的例子来说明一下。
Jsp编程有一些MVC的框架,比如Struts,Struts控制器的工作如下:首先是一个请求分派机制,负责监听请求和分配请求,然后是一个Command模式的实现,负责处理请求。首先收到服务器收到客户端的http请求,交给控制器分析其中的地址,在一个配置文件中寻找对应的处理者(一个Action的子类),建立这个类的实例,随后执行其execute方法,Action类中调用业务模块进行实际业务的处理(在处理之前进行必要的准备,比如分析请求的参数,将其转化为业务模型了解的对象),得到处理结果,根据处理的结果决定需要显示的View。这个需要显示的View在Struts框架中也是在文件中配置的。
这是一种集中式的控制器,应用程序使用一个统一的Controller。不仅使业务和界面分离开,并且界面的流程完全由同一个对象来控制。最重要的是,使得功能的修改和追加变得比较方便,控制器成为业务模块的缓冲,减轻了需求变化对业务模块的影响。
很多windows窗体程序也采用这样的控制器。有一个开放源码的.Net开发工具,叫做SharpDev,本身也是用c#开发的,采用的就是这样的集中控制方式。SharpDev是用add-in的方式进行增量开发的,程序中的功能,如打开文件、保存文件、运行某个向导等功能都是一个个独立的add-in,使用了Command模式。程序运行过程大致如下:应用程序初始化的时候,读取配置文件中所有名称为*.add-in的文件,得到程序中所有的add-in,可以把这些add-in看作一个ICommand接口的实现。根据配置文件建立这些ICommand的实例,绑定在对应的菜单项和工具栏按钮上。当用户点击这些菜单项和工具栏按钮的时候,由一个任务分派的对象将请求定位到一个Command上,执行其Run方法。Command执行的时候可能要调用业务程序,业务程序是通过一系列的Service对外提供功能的,不直接向外界暴露。Controller就是负责定向用户操作到具体Command的分派器。
窗体应用程序还有一个特点:有时候业务改变的时候,需要用户界面作出相应的变化。比如:当代码编辑器中的文字发生变更的时候,工具栏上的保存按钮要置为可用状态,当保存后,保存按钮又要置为灰色。这样的功能是通过一个Observeor模式来实现的,这就避免了业务模块对用户界面的依赖,并且这样的模式也便于同时将消息发送给多个对象,比如保存按钮不仅要在工具栏上出现,也要在菜单上出现,这样的变化是不会影响业务模块的。在SharpDev中,这个交互的过程也是在业务模块对外提供的Service中通过delegate来实现的。
成功的作品都是完善地处理了这三个界面的结晶。人面鱼设计为广大用户提供优质的软件界面设计、游戏界面设计、手机界面设计、PDA界面设计、MP3界面设计、MP4界面设计、掌上多媒体播放器界面设计、掌上学习机界面设计、网站界面设计、数字电视界面设计、电子显示屏终端界面、手机游戏设计等设计方案。