引言
MVC,即 Model(模型)-View(视图)-Controller(控制器),是广泛应用于交互式系统中的典型架构模式,尤其在 GUI 和 Web 应用中。
MVC 的概念源自 GOF(Gang of Four)的设计模式中的观察者模式(Observer Pattern),尽管 GOF 的经典设计模式中并未明确提出 MVC 这一术语。该概念由 Trygve Reenskaug 在 1979 年首次提出于其论文《Models-Views-Controllers》中。
MVC 架构通过将系统划分为三种关键组件,使其逻辑结构更清晰:
- 模型(Model):管理应用程序的核心数据和业务逻辑,独立于视图和控制器,不关心数据的显示方式或如何被操作。
- 视图(View):负责数据的呈现,通过从模型获取数据来展示给用户,不包含业务逻辑。
- 控制器(Controller):处理用户输入,更新模型并通知视图以更新展示。
经典 MVC 的这种架构分离使得用户界面(视图和控制器)与核心数据(模型)解耦。本文探讨两种主流的 MVC 模式:经典 MVC 和 Web 应用中的 MVC Model 2 模式。
经典MVC
在经典 MVC 中,视图(View)是系统的中心,它负责发起事件请求。控制器(Controller)响应这些事件请求,更新模型(Model)。当模型发生变化时,它通过观察者模式通知视图,视图则自动更新。这种模型和视图之间的交互不需要控制器参与。
经典 MVC 主要应用于桌面应用程序中,因为它的观察者模式在本地环境中表现良好。但在 Web 应用中,视图和模型分别位于浏览器端和服务器端,这种模型观察的机制很难实现。因此,经典 MVC 在 Web 应用中的适用性受到限制。
尽管如此,经典 MVC 的分层设计及其使用的设计模式(观察者模式、组合模式、策略模式)至今仍具借鉴意义。
观察者模式
经典 MVC 使用观察者模式来实现主动模型(Active Model),即当模型发生变化时,自动通知视图进行更新。例如,在一个音乐播放应用中,当用户点击播放按钮,控制器通知模型播放音乐,模型可以通过观察者模式通知视图更新播放状态。
在简单场景中,模型可以是被动的(Passive Model),例如,控制器通知视图获取数据,模型则只作为数据持有者而不主动通知视图更新。
组合模式
View和Controlle通常是分层组织的,像树状结构的布局是其典型的实现。组合模式允许将复杂的视图结构拆解为简单的子视图,从而提高系统的可维护性和复用性。
策略模式
MVC 架构的另一重要特性是,可以在不修改视图的情况下改变系统的响应逻辑。控制器可以封装不同的响应策略,通过策略模式,系统可以动态切换控制器,调整用户输入的响应方式。
Web应用MVC:Model 2
Model 2 是为适应 Web 应用的特点而对经典 MVC 进行的改进,常用于 JSP 和类似的 Web 框架中。它采用了前端控制器模式(Front Controller Pattern),即所有用户请求首先由控制器处理,控制器负责调用模型和视图,生成用户所需的内容。
在Model2模式中,Controller是系统的核心,用户所有请求被 Controller 拦截(Front Controller模式,servlet / filter)。Controller 首先响应用户输入,并更新数据到Model组件,然后从Model获取需要的数据,并整合成 View 层需要的 Domain Objects(一般包含数据和业务逻辑,POJO / JavaBean)。随后,Controller 根据结果调用适当的 View 进行展示。
每个视图都有于此相关联的控制器组件。控制器接受用户输入,用户通过控制器与系统交互,控制接收到用户输入指令,首先操作Model实现数据更新,然后Controller通知View展示最新数据,View在展示过程中会与Model通信获取最新数据。
此模式下,View 和 Model 的部分可能有多种实现。一般倾向于单向互通(即View可直接获取Model)或间接互通。
例如,在一个电子商务网站中,用户在页面上进行商品搜索操作,请求首先被控制器(Servlet)拦截。控制器调用模型(数据库操作的 JavaBean)进行商品搜索,获取结果后将数据整合成视图需要的格式,然后调用相应的 JSP 视图页面展示搜索结果。用户可以在视图页面上进一步查看商品详情,视图页面会再次与模型通信获取商品的详细信息。
Java Web Model 2
Java Web Model 2是Model 2的典型范例,在Model 2构架中,Servlet作为前端控制器,负责接收客户端发送的请求,在Servlet中只包含控制逻辑和简单的前端处理;然后调用后端JavaBean来完成实际的逻辑处理;最后转发到相应的JSP页面处理显示逻辑。
Model2中,JSP是表现层角色,仅用于将结果呈现给用户。浏览器发来的请求与Servlet(控制器)交互,而Servlet负责与后台的JavaBean通信。模型(Model)由JavaBean充当,视图(View)有JSP页面充当,而控制器(Controller)则由Servlet充当。
优缺点
优点
低耦合性
视图层与业务层分离,使得更改视图层代码无需重新编译模型和控制器代码。同样,应用程序的业务流程或业务规则改变只需改动 MVC 的模型层。由于模型与控制器和视图相分离,改变应用程序的数据层和业务规则变得容易。
高重用性和可适用性
随着技术的不断进步,现在需要用越来越多的方式来访问应用程序。MVC模式允许你使用各种不同样式的视图来访问同一个服务器端的代码。它包括任何WEB(HTTP)浏览器或者无线浏览器(wap),比如,用户可以通过电脑也可通过手机来订购某样产品,虽然订购的方式不一样,但处理订购产品的方式是一样的。由于模型返回的数据没有进行格式化,所以同样的构件能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这些表示所需要的命令是改变视图层的实现方式,而控制层和模型层无需做任何改变。
较低的生命周期成本
MVC使开发和维护用户接口的技术含量降低。
快速的部署
使用MVC模式使开发时间得到相当大的缩减,它使程序员(Java开发人员)集中精力于业务逻辑,界面程序员(HTML和JSP开发人员)集中精力于表现形式上。
可维护性
分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。
有利于软件工程化管理
由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化管理程序代码。
缺点
复杂性
MVC 架构虽然提高了系统的模块化,但也带来了额外的复杂性,特别是在小型项目中,可能过于臃肿。
调试困难
由于视图、控制器和模型是相互独立的,调试时可能需要跨多个模块进行排查,增加了调试的难度。
总结
MVC 首次将心智模型与数字模型建立联系,同时将代码逻辑进行分层,将「渲染」「控制 / 分发」与数据存储进行有机分隔。此后,在涉及界面展示的编程领域,人们大概率会想到 MVC 的分隔方式并依此实现。因此,MVC 存在各种变种和通信方式,如 Backbone JS 中 View 和 Model 之间可以相互更改;Cocoa MVC 中 View 和 Controller 之间、Controller 和 Model 之间相互更改。