现在的位置: 首页 > 综合 > 正文

mvc模式

2018年02月14日 ⁄ 综合 ⁄ 共 9783字 ⁄ 字号 评论关闭




MVC

模式

  

 

MVC

架构是"Model-View-Controller"
的缩写,中文翻译为"
模式-
视图-
控制器"
MVC
应用程序总是由这三个部分组成。 Event(
事件)
导致Controller
改变Model
View
,或者同时改变两者。


只要Controller
改变了Models
的数据或者属性, 所有依赖的View
都会自动更新。类似的,只要Controller
改变了View
View
会从潜在的Model
中获取数据来刷新自己。MVC
架构最早 是smalltalk
语言研究团提出的,应用于用户交互应用程序中。smalltalk
语言和java
语言有很多相似性,
都是面向对象语言,很自然的 SUN
petstore(
宠物店)
事例应用程序中就推荐MVC
架构作为开发Web
应用的架构模式



MVC
架构是一种架构,其实需要其
他模式协作完成。在J2EE
模式目录中,通常采用service to
worker

模式实现,而service to worker
模式可由集中控制器模式,派遣器模式和Page Helper
模式组成。而Struts
只实现了MVC
View
Controller
两个部分,Model
部分需要开发者自己来实现,Struts
提供 了抽象类Action
使开发者能将Model
应用于Struts
框架中。

  MVC
架构是一个复杂的架构,其实现也显得非常复杂。但是,我们已经总结出了很多可靠的设计模式



,多种 设计模式结合在一起,使MVC
架构的实现变得相对简单易行。Views
可以看作一棵树,显然可以用Composite Pattern
来实现。Views
Models
之间的关系可以用Observer
Pattern

体现。Controller
控制Views
的显示,可以用Strategy Pattern
实现。Model
通常是一个调停者,可采用Mediator Pattern
来实现。

  现在让我们来了解一下MVC
三个部分在J2EE
架构中处于什么位置,这样有助于我们理解MVC
架构的实现。MVC
J2EE
架构的对应关系是:View
处于Web Tier
或者说是Client
Tier

,通常是JSP/Servlet
,即页面显示部分。Controller
也处于Web Tier
,通常用Servlet
来实现,即页面显示的逻辑部分实现。Model
处于Middle Tier
,通常用服务端的javaBean
或者EJB
实现,即业务逻辑部分的实现。

 

 一、MVC
设计思想

  MVC
英文即Model-View-Controller
,即把一个应用的输入、处理、输出流
程按照Model
View
Controller
的方式进行分离,这样一个应用被分成三个层——
模型层、视图层、控制层。

  视图(View)
代表用户交互界面,对于Web
应用来说,可以概括为HTML
界面,但有可能为 XHTML
XML
Applet
。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC
设计模式对于视图的处理 仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)
处理。比如一个订单的视图只 接受来自模型的数据并显示给用户,以及将用户界面的输入数据和请求传递给控制和模型。


  模型(Model)
:就是业务流程/
状态的处理以及业务规则的制定。业务流程的处理过程对其它
层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。
业务模型的设计可以说是MVC
最主要的核心。目前流行的EJB
模型就是一个典型的应用 例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉你按这种模型设计就可以利用
某些技术组件,从而减少了技术上的困难。对一个开发者来说,就可以专注于业务模型的设计。MVC
设计模式告诉我们,把应用的模型按一定的规则抽取出来,抽
取的层次很重要,这也是判断开发人员是否优秀的设计依据。抽象与具体不能隔得太远,也不能太近。MVC
并没有提供模型的设计方法,而只告诉你应该组织管理
这些模型,以便于模型的重构和提高重用性。我们可以用对象编程来做比喻,MVC
定义了一个顶级类,告诉它的子类你只能做这些,但没法限制你能做这些。这点
对编程的开发人员非常重要。

  业务模型还有一个很重要的模型那就是数据模型。数据模型主要指实体对象的数据 保存(持续化)
。比如将一张订单保存到数据库,从数据库获取订单。我们可以将这个模型单独列出,所有有关数据库的操作只限制在该模型中。

  控制(Controller)
可以理解为从用户接收请求,
将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以
完成什么样的用户请求。控制层并不做任何的数据处理。

例如,用户点击一个连接,控制层接受请求后,
并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个
模型。

  模型、视图与控制器的分离,使得一个模型可以具有多个显示视图。如果用户通过某个视图的控制器
改变了模型的数据,所有其它依赖于这些数据的视图都应反映到这些变化。因此,无论何时发生了何种数据变化,控制器都会将变化通知所有的视图,导致显示的更 新。这实际上是一种模型的变化-
传播机制。模型、视图、控制器三者之间的关系和各自的主要功能,如图1
所示。

 

 二、MVC
设计模式的实现

  ASP.NET
提供了一个很好的实现这种经典设计模式的类似环境。开发者通过在ASPX
页面中
开发用户接口来实现视图;控制器的功能在逻辑功能代码(.cs)
中实现;模型通常对应应用系统的业务部分。在ASP.NET
中实现这种设计而提供的一个多 层系统,较经典的ASP
结构实现的系统来说有明显的优点。将用户显示(视图)从动作(控制器)中分离出来,
提高了代码的重用性。将数据(模型)从对其操作 的动作(控制器)分离出来可以让你设计一个与后台存储数据无关的系统。就MVC
结构的本质而言,它是一种解决耦合系统问题的方法。

  MFC

  微软所推出的MFC Document/View
架构是早期对于MVC
实现,MFC
将程序分成CView
以及CDocument
两大类,其中的Document
对应MVC
中的
Model

View
相当于MVC
中的View
Controller
,再加上CWinApp
类,合成三大项。但是基本上MFC
是一个失败的MVC
作品。

  由于MFC
之下的Document/View
定义过于模糊,未将 Controller
MessageMap
)部份取出,因此Controller
可以置入View
Document
,但不管置入哪一方面,都会与 View
Document
绑死,没有弹性。

  Java

  Java
平台企业版 (J2EE)
和其他的各种框架不一样,J2EE
为模型对象(Model Objects)
定义了一个规范。

  视图(View)

  在J2EE
应用程序中,视图(View)
可能由Java Server Page(JSP)
承担。生成视图的代码则可能是一个servlet
的一部分,特别是在客户端服务端交互的时候。

  控制器(Controller)

  J2EE
应用中,控制器可能是一个servlet
,现在一般用Struts
实现。

  模型(Model)

  模型则是由一个实体Bean
来实现。

  2.1
视图

  视图是模型的表示,它提供用户交互界面。使用多个包含单显示页面的用户部件,复杂的Web
页面 可以展示来自多个数据源的内容,并且网页人员,美工能独自参与这些Web
页面的开发和维护。

  在ASP.NET
下,视图的实现很简单。可以像开发WINDOWS
界面一样直接在集成开发环境
下通过拖动控件来完成页面开发本。本文中介绍每一个页面都采用复合视图的形式即:一个页面由多个子视图(
用户部件)
组成;子视图可以是最简单HTML
控件、服务器控件或多个控件嵌套构而成的Web
自定义控件。页面都由模板定义,模板定义了页面的布局,用户部件的标签和数目,用户指定一个模板,平台根据 这些信息自动创建页面。针对静态的模板内容,如页面上的站点导航,菜单,友好链接,这些使用缺省的模板内容配置;针对动态的模板内容(
主要是业务内容)
, 由于用户的请求不同,只能使用后期绑定,并且针对用户的不同,用户部件的显示内容进行过滤。使用由用户部件根据模板配置组成的组合页面,它增强了可重用
性,并原型化了站点的布局。

  视图部分大致处理流程如下:首先,页面模板定义了页面的布局;页面配置文件定义视图标签的具体
内容(用户部件);然后,由页面布局策略类初始化并加载页面;每个用户部件根据它自己的配置进行初始化,加载校验器并设置参数,以及事件的委托等;用户提 交后,通过了表示层的校验,用户部件把数据自动提交给业务实体即模型。

  这一部分主要定义了WEB
页面基类PageBase
;页面布局策略类PageLayout
,完 成页面布局,用于加载用户部件到页面;用户部件基类UserControlBase
即用户部件框架,用于动态加载检验部件,以及实现用户部件的个性化。为
了实现WEB
应用的灵活性,视图部分也用到了许多配置文件例如:置文件有模板配置、页面配置、路径配置、验证配置等。

  2.2
控制器

  为了能够控制和协调每个用户跨越多个请求的处理,控制机制应该以集中的方式进行管理。因此,为
了达到集中管理的目的引入了控制器。应用程序的控制器集中从客户端接收请求(典型情况下是一个运行浏览器的用户),决定执行什么商业逻辑功能,然后将产生 下一步用户界面的责任委派给一个适当的视图组件。

  用控制器提供一个控制和处理请求的集中入口点,它负责接收、截取并处理用户请求;并将请求委托
给分发者类,根据当前状态和业务操作的结果决定向客户呈现的视图。在这一部分主要定义了HttpReqDispatcher(
分发者类)
HttpCapture(
请求捕获者类)
Controller(
控制器类)
等,它们相互配合来完成控制器的功能。请求捕获者类捕获HTTP
请求并转发给 控制器类。控制器类是系统中处理所有请求的最初入口点。控制器完成一些必要的处理后把请求委托给分发者类;分发者类分发者负责视图的管理和导航,它管理将
选择哪个视图提供给用户,并提供给分发资源控制。在这一部分分别采用了分发者、策略、工厂方法、适配器等设计模式。

  为了使请求捕获者类自动捕获用户请求并进行处理,ASP.NET
提供低级别的请求/
响应
API

,使开发人员能够使用 .NET
框架类为传入的 HTTP

请求提供服务。为此,必须创作支持 System.Web.IHTTPHandler
接口和实现 ProcessRequest()
方法的类即:请求捕获者类,并在web.config

httphandlers
> 节中添加类。ASP.NET
收到的每个传入 HTTP
请求最终由实现 IHTTPHandler
的类的特定实例来处理。IHttpHandlerFactory
提供了处理 IHttpHandler
实例 URL
请求的实际解析的结构。HTTP
处理程序和工厂在 ASP.NET
配置中声明为 web.config
文件的一部分。ASP.NET
定义了一个 <httphandlers
> 配置节,在其中可以添加和移除处理程序和工厂。子目录继承 HttpHandlerFactory
HttpHandler
的设置。 HTTP
处理程序和工厂是 ASP.NET
页框架的主体。工厂将每个请求分配给一个处理程序,后者处理该请求。
例如,在全局 machine.config
文件中,ASP.NET
将所有对 ASPx
文件的请求映射到 HttpCapture
类:

  <httphandlers

  ...

  ...

  </httphandlers

  2.3
模型

  MVC
系统中的模型从概念上可以分为两类――
系统的内部状态和改变系统状态的动作。模型是你所
有的商业逻辑代码片段所在。本文为模型提供了业务实体对象和业务处理对象:所有的业务处理对象都是从ProcessBase
类派生的子类。业务处理对象封
装了具体的处理逻辑,调用业务逻辑模型,并且把响应提交到合适的视图组件以产生响应。业务实体对象可以通过定义属性描述客户端表单数据。所有业务实体对象 都EntityBase
派生子类对象,业务处理对象可以直接对它进行读写,而不再需要和request
response
对象进行数据交互。通过业务实体 对象实现了对视图和模型之间交互的支持。实现时把"
做什么"
(业务处理)和"
如何做"
(业务实体)分离。这样可以实现业务逻辑的重用。由于各个应用的具体
业务是不同的,这里不再列举其具体代码实例。

 

 三、MVC
设计模式的扩展

  通过在ASP.NET
中的MVC
架构编写的,具有极其良好的可扩展性。它可以轻松实现以下功
能:

  
实现一个模型的多个视图;

  
采用多个控制器;

  
当模型改变时,所有视图将自动刷新;

  
所有的控制器将相互独立工作。

  这就是MVC
架构的好处,只需在以前的程序上稍作修改或增加新的类,即可轻松增加许多程序功 能。以前开发的许多类可以重用,而程序结构根本不再需要改变,各类之间相互独立,便于团体开发,提高开发效率。下面讨论如何实现一个模型、两个视图和一个
控制器的程序。其中模型类及视图类根本不需要改变,与前面的完全一样,这就是面向对象编程的好处。对于控制器中的类,只需要增加另一个视图,并与模型发生 关联即可。该模式下视图、控制器、模型三者之间的示意图如图2
所示。

  同样也可以实现其它形式的MVC
例如:一个模型、两个视图和两个控制器。从上面可以看出,通过 MVC
架构实现的应用程序具有极其良好的可扩展性,是ASP.NET
面向对象编程的未来方向。

  四、MVC
的优点

  大部分用过程语言比如ASP
PHP
开发出来的Web
应用,初始的开发模板就是混合层的数据编
程。例如,直接向数据库发送请求并用HTML
显示,
开发速度往往比较快,
但由于数据页面的分离不是很直接,
因而很难体现出业务模型的样子或者模型的重用
性。产品设计弹性力度很小,很难满足用户的变化性需求
MVC
要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好
地体现


  首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种
方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按 MVC
设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。
其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。

  再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变
。一个应用的业务 流程或者业务规则的改变只需改动MVC
的模型层。

  控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制 层可以说是包含了用户请求权限的概念。

最后,它还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特
征,有利于通过工程化、工具化产生管理程序代码。

各施其职,互不干涉

MVC
模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。
  



有利于开发中的分工
   

MVC
模式中,由于按层把系统开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP
,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。


 
 


有利于组件的重用

   

分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视图层也可做成通用的操作界面。

  五、MVC
的不足

  MVC
的不足体现在以下几个方面:

  (1
)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC
,使模型、视图与控制器
分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

  (2
)视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但确实联系紧密的部件,视图 没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

  (3
)视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足 够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

  (4
) 目前,一般高级的界面工具或构造器不支持MVC
架构。改造这些工具以适应MVC
需要和建立分离的部件的代价是很高的,从而造成使用MVC
的困难。

 

 

 

 

请简述你对
MVC
模式的理解回答:
MVC
模式是表示层开发最常用的设计模式,使用这个设计模式的目的是为了解除控制逻辑,业务逻辑和视图之间的耦合,提升系统的可扩展性和可维护性。
MVC
模式主要由模型,控制器和视图三个部分组成。其中控制器的主要责任是接受客户所提交的请求,并将请求转发给适当的模型对象进行处理,再将处理的结果发给视图
,进行显示。在

J2EE
项目当中,通常会使用
Servlet
来担任这个角色,因为在
Servlet
当中可以直接使用
HttpServletRequest,HttpServletResponse

API
。模型的主要作用是根据客户的请求来进行相应的业务运算,这个部分的功能在
J2EE
当中主要使用
JavaBean
来完成,这部分的代码不能依赖于
Servlet API
,从而可以保证业务逻辑的可移植性。控制器将模型运算的结果发送到视图,视图负责将这部分数据显示给客户。这个部分的功能在
J2EE
当中主要是使用
JSP
来完成。因为
JSP
可以在允许在
HTML
当中插入
Java
代码。

 

Web

应用的

MVC

和经典的

MVC

显著不同



MVC

早期出现在桌面应用中。由于桌面应用的各个部分都运行在同一个进程(即便是后来流行的
C/S
应用,很大程度上也可以假想为同一逻辑进程)中,所以应用程序各个部分之间的交互都视为

可信任的



经典的
MVC

C
返回一个合适的
V

V
里面调用
M
获得数据,如果有什么
UI
上的事件发生,也是
V
里面直接去操作
M
了。因此在经典
MVC
中,应用程序逻辑是主要放到
V
中的。
C
只完成应用程序逻辑中的小部分(分发不同的
V
)。由于大部分应用程序逻辑是在
V
里面实现,所以
V
还要维持一个内部状态。


就拿大家前面的例子:输入框如果输入错误的数据,应该变成红色。


这个需求是典型的应用程序逻辑(更可以具体为一个
UI
逻辑),所以最好的实现场所就是
V
里面。在经典
MVC
中,控件输入数据会引发一系列的事件,而
V
可以拦截控件的
onchange
事件,从而设置控件的颜色。后来更进一步,将控件封装为对象,从而让控件对象负责自己的逻辑,
V
就不用操心这些细节了。


到了
Web

时代,
MVC

就变了


最关键的一点就是应程序被分成了浏览器端和服务端两部分。



MVC
的影响就是
V
现在也被分成了两部分,一部分放在浏览器端,一部分放在服务端。


还是那个输入框的例子,
Web

应用处理起来有多种方式:

1
、输入改变后,什么都不管,直到提交表单后,服务端对数据进行验证。如果验证失败,再重新构造整个用户界面,并且将输入框的属性改成红色。这个过程中,
V
完全是被动的,仅仅是负责渲染

HTML

而已。

2

、输入改变后,通过
Ajax

请求提交这个控件的数据,让服务端对数据进行验证。服务端返回特定的数据(例如一个
JSON
)指示验证是否通过,
V
里面的
JS
代码则根据返回结果更新输入框的颜色。

3

、输入改变后,提交整个表单。然后服务端根据客户端的事件调用服务端的事件处理方法。事件处理方法中对控件数据进行验证,再更新控件的属性。最后服务端重新构造整个页面。

4

、输入改变后,客户端的
JS

直接验证并更新控件状态。但整个表单提交到服务器后,还是得一一验证。


第一种是最传统的,也是最常用的。第二种则是
Ajax
兴起后流行的,不过现在大家也在反思这种模式是不是造成太多对服务器的请求。第三种则是
ASP.NET

POSTBACK
机制,
JSF
我不了解,看介绍也是类似的机制。第四种实际上只是第一种的变形。


第一种模式:浏览器端完全不负责任何逻辑,仅仅是提供一个输入数据的接口,然后可以把数据提交到服务端。应用程序逻辑完全在服务端里面实现。


这种模式里面,
V
实际上只是一个模板。服务端的
C
负责响应请求,然后验证浏览器端提交的数据,再调用
M
进行处理。最后根据处理结果,载入模板,渲染出
HTML
返回给浏览器。


第一种模式容易理解,而且实现简单,对浏览器端没有特殊要求,所以一直以来都是最主要的处理模式。但缺点就是用户体验不好,对用户操作不会有及时的反馈,而且没有办法根据用户操作实时的更新
UI


第二种模式:浏览器端稍微主动点,会把
UI
事件报告给服务端。服务端处理后再反馈特定信息给浏览器端,浏览器端从而可以更新
UI



比起第一种模式,第二种模式中的
V
会包含一些

JavaScript

代码。这些
JS
代码负责响应
UI
事件,然后把事件及相关的数据传递到服务端,并等待服务端的响应。服务端还是由
C
来处理,只不过处理完成之后仅仅是把处理结果返回给浏览器端(
XML

JSON
、字符串或者
JS
代码)。浏览器端的
JS
收到服务端的响应后,根据处理结果对
UI
做相应的更新。


这种模式的相对第一种来说有了不小的进步。用户操作可以马上得到反馈,而且可以构造非常动态的
UI
。缺点则是需要编写大量的

JS

代码,服务端也要增加对应的响应代码。而且不同浏览器对
JS
的支持程度也不同,实践起来即使有各种
JS
框架的帮助也是比较繁琐的。


第三种模式:这种模式一个页面就是一个表单,
JS
会去响应表单中的
UI
事件,然后根据事件类型决定是立即提交整个表单,还是稍后提交。


当表单提交后,服务端就不再是一个常规意义上的
C
来处理了,而是一个页面控制器(可以看作更复杂的
C
)。页面控制器会根据定义,构造出整个页面的对象体系(例如
Page
对象中有两个
Textbox

对象)。构造好对象体系后,页面控制器会解析提交的表单中包含的事件。然后调用各个控件的事件响应方法。此时,就和桌面应用非常接近了。我们可以给各个控件编写事件响应代码,并在事件响应代码中调用
M
处理数据。当所有的事件都处理完成后,页面控制器会载入模板,然后传入对象体系,并通过复杂的渲染机制,将
UI
内容渲染出来返回给浏览器。


这种模式的好处很明显,那就是应用程序逻辑都在
V
里面完成。而且控件封装为了对象,控件的逻辑可以自己负责。缺点就是每次提交都是提交整个表单,数据量较大时明显会增加通讯量和延迟。而且早期的
Web
应用事件驱动模型会导致每次提交都重新构造整个页面,用户体验和效率也不怎么样。好在后来都有所改进,使用
Ajax
来提交表单和更新用户界面。


在上述三种模式中,我们会发现一个共同点:绝不在浏览器端实现应用程序逻辑。


因为浏览器端是不可控的运行环境,如果应用程序逻辑在浏览器端实现,那么安全性就得不到保证了。比如批量删除操作这个应用程序逻辑如果在浏览器端实现,用户完全可以自己分析浏览器端的代码和逻辑,直接构造一个表单来提交,从而绕过各种验证。


但是不在浏览器端实现应用程序逻辑,不代表不可以在
V
里面实现应用程序逻辑。要记住在
Web
应用中,
V
是可以分成多个部分的,并且分别运行在服务端和浏览器端的,而且在服务端实现

V

也有很多种模式。实际上第三种模式就是典型,
V
运行在服务端,并且完成所有的应用程序逻辑。


在服务端
V

中实现应用程序逻辑



比如我们可以在模板中写入应用程序逻辑,然后模板引擎解析模板时,通过嵌入模板的
tag
来调用
M
获得要呈现的数据。这种方式已经非常非常多的实现了,实际应用时对于显示各种数据是很方便的。但是这种模式没办法主动响应用户操作。所以后来出现的事件驱动才是最完整(但不是最完善)的解决方案。


可惜由于
Web
应用的天然特性,事件驱动不管怎么改善,都绕不开将整个表单提交到服务器的过程。所以事件驱动在
Web
应用上一直都没有成为主流。

 

 

抱歉!评论已关闭.