在前面简述了从服务层到数据层参见架构设计目录。剩下了表现层,一个再好的中间层表现也必须有一个用户界面,提供和用户交互,将用户行为输入转化为系统操作,进入后台逻辑。在当下RAD(快速应用开发)工具的支持下,我们可以比较快速的完成UI设计,RAD追求所见即所得的快速反馈,快速应用。表现层也有一定其固定的逻辑(格式化,数据绑定,转化等等,称为UI逻辑)和界面展现。这里UI逻辑指的是所有用来处理数据显示在UI界面的逻辑和,将UI用户输入行为转化为中间层指令的逻辑,负责UI和中间层数据流和行为的转化。很多时候UI是最容易变化的以及最不易测试的逻辑(我一直相信,1:一段好的代码一定要易于测试。2:重构的前提也必须有足够的测试保证,才能让我们的重构更有节奏更自信),而很大部分UI逻辑却往往比较稳定的。这Matin Fowler提出的分离表现层模式。表现层模式主要分为3种大类:MVC,MVP,PM(微软在sl和wpf起名为MVVM),这3类模式下延伸了很多变异体mvc在web的 model2(asp.net mvc,主要特征基于web特有uri路由)。mvp的变种:Passive View(被动视图)和Supervising Controller(不清楚怎么翻译比较好),PM延伸MVVM。其目的都在于将多变的View和UI逻辑分离。
今天要说的是MVC(model-view-controller:模型-视图-控制器)。在我们一开始就说结构和编程或者面向对象原则都是为了实现模块的高内聚低耦合,而高内聚低耦合行之有效的方式就是分离关注点(SOC)。为了实现表现UI和表现逻辑的分离,使得他们之间更灵活,并且自治视图(包含所有表现层代码的类)。在30年前Trygve Reenskaug提出的MVC模式,或者更确切的说模范。其将表现层分为3类:model:是视图展现数据,view用户交互界面,Controller:将用户输入转化为中间层操作。
模型(Model):在MVC中模型保持着一个应用程序的状态,和相应视图中来自用户交互的状态变化。在上图中我们可以看到model会接受来之控制器的状态变化响应和视图的显示状态查询view渲染的数据来源。同时model还有通过事件机制(观察者模式)通知view状态的改变要求view渲染响应。view和模型之间存在一定的耦合,view必须了解model,这也是MVP模式出现原因之一。正在这里的模型model可以是来之分布式soap或者resetfull的dto(数据传输对象),也可以直接是我们的领域对象(do)或者数据层返回的数据集,并不严格的 要求。
控制器(Controller):控制器是又view触发,响应用户界面的交互,并根据表现层逻辑改变model状态,以及中间层的交互,最终修改model,Controller不会关心视图的渲染,是通过修改model,model的事件通知机制,触发view的刷新渲染。控制器和模型的交互式一种“发出即忘”,或者分布式OneWay的调用。控制器Controller不会主动了了解view和view交互,除了唯一的视图选择外,控制器需要选择下一次显示的视图view是什么。一般控制器会请求全局应用程序路由下一个需要显示的view,在使其呈现出来。
视图(View):视图时表现层模式出现的原因,因为他的多样性和变化的频繁性,不易测试(太多外界环境依赖),所以理想的视图应该尽可能的哑,被动,视图只负责渲染呈现给用户交互。视图由一些列GUI组件组成,响应用户行为触发控制器逻辑,修改model状态使其保持view同步。视图并需要相应model的变化被动的接受model状态变化刷新相应给用户。
MVC最先兴起于桌面,但没有流行起来,知道在web兴起后,其变异体Model2在Web中流行起来,.net 下的ASP.NTE MVC。Model2中,将来自客户端(浏览器)的请求,被服务端拦截器(asp.net中HttpModule)根据url格式请求方式等转发到固定的控制器,调用固定的Action,在Action中队模型状态进行修改,并选择view,view并根据控制器传来的最新model生产html,css,js前段代码,并输出到前段渲染。
在Model2中和原始MVC最大的差别在于:
1:视图view和模型model之间没有直接依赖,model并不知道view也不需要事件通知view,view也不需知道model,view操作的都是ViewModel(asp.net mvc 中ViewData容器)。2:控制器显示传入视图数据给view,相应用户的操作不是来自view,而是出于服务端应用程序前段的拦截器,捕获url并转发到相应的控制器,已经调用相应的action方法。
在现在说的MVC往往指的就是Web中Model2模式。在Model2中view是被动的,哑的,简单。