本條目存在以下問題,請協助改善本條目或在討論頁針對議題發表看法。 此條目的语调或风格或許不合百科全書。 (2020年12月25日)請根據指南協助改善这篇条目,並在讨论页討論問題所在,加以改善。 此條目包含過多行話或專業術語,可能需要簡化或提出進一步解釋。 (2016年6月3日)請在討論頁中發表對於本議題的看法,並移除或解釋本條目中的行話。 此條目需要补充更多来源。 (2022年3月23日)请协助補充多方面可靠来源改善这篇条目无法查证的内容可能會因為异议提出而被移除。致使用者:请搜索一下条目的标题(来源搜索:"MVC"网页新闻书籍学术图像),以检查网络上是否存在该主题的更多可靠来源(判定指引)。 此條目需要編修,以確保文法、用詞、语气格式標點等使用恰当。 (2022年5月31日)請按照校對指引,幫助编辑這個條目。(幫助討論

MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

MVC模式最早由Trygve Reenskaug在1978年提出[1],是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构。MVC模式的目的是实现一种动态的程式设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式透过对复杂度的简化,使程序结构更加直观。软件系统透过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。专业人员可以依據自身的专长分组:

MVC模式

组件的互动

MVC组件之间的典型合作

将应用程序划分为三种组件,模型 - 视图 - 控制器(MVC)设计定义它们之间的相互作用。[2]

优点

在最初的JSP网页中,像数据库查询语句(SQL query)这样的数据层代码和像HTML这样的表示层代码是混在一起。虽然有着经验比较丰富的开发者会将数据从表示层分离开来,但这样的良好设计通常并不是很容易做到的,实现它需要精心地计划和不断的尝试。MVC可以从根本上强制性地将它们分开。尽管构造MVC应用程序需要一些额外的工作,但是它带给我们的好处是毋庸置疑的。

首先,多个 View 能共享一个 Model 。如今,同一个Web应用程序会提供多种用户界面,例如用户希望既能够通过浏览器来收发电子邮件,还希望通过手机来访问电子邮箱,这就要求Web网站同时能提供Internet界面和WAP界面。在MVC设计模式中, Model 响应用户请求并返回响应数据,View 负责格式化数据并把它们呈现给用户,业务逻辑和表示层分离,同一个 Model 可以被不同的 View 重用,所以大大提高了代码的可重用性。

其次,Controller 是自包含(self-contained,指高獨立內聚)的物件,与 Model 和 View 保持相对独立,所以可以方便的改变应用程序的数据层和业务规则。例如,把数据库从MySQL移植到Oracle,或者把RDBMS数据源改变成LDAP数据源,只需改变 Controller 即可。一旦正确地实现了控制器,不管数据来自数据库还是LDAP服务器,View 都会正确地显示它们。由于MVC模式的三个模块相互独立,改变其中一个不会影响其他两个,所以依据这种设计思想能构造良好的少互扰性的构件。

此外,Controller 提高了应用程序的灵活性和可配置性。Controller 可以用来连接不同的 Model 和 View 去完成用户的需求,也可以构造应用程序提供强有力的手段。给定一些可重用的 Model 、 View 和Controller 可以根据用户的需求选择适当的 Model 进行处理,然后选择适当的的 View 将处理结果显示给用户。

评价、誤解及适用范围

MVC模式在概念上强调 Model, View, Controller 的分离,各個模組也遵循著由 Controller 來處理訊息,Model 掌管資料來源,View 負責資料顯示的職責分離原則,因此在實作上,MVC 模式的 Framework 通常會將 MVC 三個部份分離實作:

也因為 MVC 模式強調職責分離,所以在發展 MVC 應用時會產生很多檔案,在 IDE (整合開發環境) 不夠成熟時它會是個問題,但在現代主流 IDE 都能使用類別物件的資訊來組織程式碼編輯的情況下,多檔案早已不是問題,而且 MVC 模式會要求開發者進一步思考應用程式的架構 (Application Architecture),而非用大雜燴的方式開發應用程式,對於應用程式的生命週期以及後續的可擴充與可維護性而言有相當正面的幫助。另外,MVC 職責分離也帶來了一個現代軟體工程要求的重要特性:可測試性 (Testability),MVC-based 的應用程式在良好的職責分離的設計下,各個部份可獨立行使單元測試,有利於與企業內的自動化測試、持續整合 (Continuous Integration) 與持續交付 (Continuous Delivery) 流程整合,減少應用程式改版部署所需的時間。

MVC 模式的應用程式的目的就是希望打破以往應用程式使用的大雜燴程式撰寫方式,並間接誘使開發人員以更高的架構導向思維來思考應用程式的設計,因此對於一個剛入門的初學者來說,架構導向的思考會有一定的門檻,需要較多的實作與練習才能具備相應的能力,大多數的初學者還是較習慣於大雜燴式的程式撰寫,所以可能會對 MVC 模式抱持著排斥或厭惡的心態,然而 MVC(或是其他的设计模式)都是有助於應用程式長遠的發展,雖然大雜燴式的程式也可以用來發展長生命週期的應用程式,但是相較於 MVC,大雜燴式的程式在可擴充性和可維護性 (尤其是可測試性) 上會遠比 MVC 複雜很多,相反的,MVC 模式的應用程式是在初始開發時期必須先思考並使用軟體架構,使得開發時期會需要花較多心力,但是一旦應用程式完成後,可擴充性、可維護性和可測試性反而會因為 MVC 的特性而變得容易。

因此,MVC 模式在已有眾多優秀 Framework 的現代,早就已經沒有不適合小型應用的問題,小型的應用還是可以由 MVC Framework 的應用來獲取 MVC 的優點,同時它也能作為未來小型應用擴充到大型應用時的基礎與入門磚。若一開始就想要做大型應用,那麼 MVC 模式的職責分離以及要求開發的架構思考會更適合大型應用的開發。

实际范例

这里有一个通过 JavaScript 所实现的基于 MVC 模型,需要注意的是:MVC 不是一种技术,而是一种理念。

/** 模拟 Model, View, Controller */
var M = {}, V = {}, C = {};

/** Model 负责存放资料 */
M.data = "hello world";

/** View 负责将资料输出给用户 */
V.render = (M) => { alert(M.data); }

/** Controller 作为连接 M 和 V 的桥梁 */
C.handleOnload = () => { V.render(M); }

/** 在网页读取的时候呼叫 Controller */
window.onload = C.handleOnload;

在这个简短的程序中就是一个完整的 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)擔任。生成 View 的代码则可能是一个servlet的一部分,特别是在客户端服务端交互的时候。
控制器(Controller)
J2EE应用中,Controller 可能是一个servlet
除了可直接以J2EE來撰寫外,亦可用其他框架來撰寫,常見的有Struts2Spring Framework……等等。
模型(Model)
Model 则是由一个实体Bean来实现。

Java Swing

Swing是一个标准的MVC结构。ComponentUI代表View,负责描画组件。组件尤其Model层,比如JTextField的Document、JTable的TableModel、JTree的TreeModel等等。Control可能不是很明显,我们可以将Event机制看作Swing团队為开发者設計的Controller。

作为Java开发者,如果想理解MVC的结构,学习Swing的确是个不错的选择。

.NET

ASP.NET

在ASP.NET中,针对视图(View)和控制器(Controller)的模式没有被很好地定义。而模型(Model)则留给开发者去设计。

视图(View)
ASPX和ASCX文件被用来处理 View 的职责。在这个设计中 View 实际上是从 Controller 继承而来。这个和Smalltalk的实施有所不同,在Smalltalk中不同的类都有指针互相指向对方。
控制器(Controllers)
Controller 的职责被分割成两部分。事件(Event)的产生和传输是框架的一部分,更明确的说是Page和Control两个类。而事件的处理则在分离的代码中实现。一般说来,控制器是部件,用来处理用户交互、对model施加工作、最终选择view来绘制。对于MVC应用程序,view只显式信息;控制器处理和响应用户的输入和交互。
模型(Model)
ASP.NET 不严格需要一个 Model。开发者可以自行选择创建一个 Model 类,但是很多人选择放弃这一步,直接把事件处理放在 Controller 里处理任何计算、数据保存等等。但用 Model 来包含商业逻辑和数据存取是可实现的。一般说来,MVC应用程中的Model表示应用程序的状态、应用程序能执行的任何业务逻辑或操作。强类型的views典型使用ViewModel类型来包含显示在该view中的数据。控制器从model创建并保有这些ViewModel实例。

ASP.NET MVC

2013年10月17日ASP.NET MVC发表了穩定版本5.0。[3]

在ASP.NET MVC中,一般情況下Model通常搭配LINQ to SQL類別(使用O/R Designer工具所製作而成的DBML檔)或ADO.NET實體資料模型(Entity Data Model,使用ADO.NET Entity Framework製作出的EDMX檔)來實作。

ASP.NET Core MVC

随着.NET Core的发布,2016年5月17日发布了ASP.NET Core MVC 1.0.0-rc2。现已发展为ASP.NET Core MVC 6。

Windows Forms

在WinForms中,这个针对视图(View)和控制器(Controller)的模式已经很好的定义。而模型(Model)则留给开发者去设计。

视图(View)
由Form或者Control类继承来的一个类处理 View 的职责。在WinForm这个例子中 View 和 Controller 被编译在同一个类中,这个和ASP.NET不同。
控制器(Controller)
Controller 的职责被分割成三部分。事件(Event)的产生和传输是操作系统的一部分。在.Net框架中Form和Control类将不同的事件转发给相应的事件处理器。而事件的处理则在分离的代码中实现。
模型(Model)
就像ASP.NET一样,WinForm不严格需要一个 Model。开发者可以自行选择创建一个 Model 类,但是很多人选择放弃这一步,直接把事件处理放在 Controller 里处理任何计算、数据保存等等。也就是说用Model来包含商业逻辑和数据存取。

Perl

Catalyst和Jifty是透過Perl語言所開發出來的Web Framework,都採用Model-View-Controller 架構。Catalyst 本身只是做了 Controller,View 和 Model 讓開發者自由選用 CPAN 上的模組開發,例如 Template 和 Template Declare 都可用來產生視圖。Jifty 將 MVC 完全實做完成,View 的部份在早期版本使用 Mason 實做,較新版本使用 Template Declare。

Ruby on Rails

Ruby on Rails是透過Ruby語言所開發出來的 Web Framework,也是採用 Model-View-Controller 架構。Model 部份使用 Active Record 概念實做,加上 Migration 機制,使得其 Model 結構非常容易控制。

Python

Python 有許多的 MVC 架構。最常用的有 DjangoTurboGears

JavaScript

PHP

ActionScript 3

參考

参考文献

  1. ^ Reenskaug, Trygve. THING-MODEL-VIEW-EDITOR: an Example from a planningsystem (PDF). [2013年4月30日]. (原始内容存档 (PDF)于2017年9月21日). 
  2. ^ Buschmann, Frank (1996) Pattern-Oriented Software Architecture.
  3. ^ ASP.NET MVC 概觀. [2010-11-04]. (原始内容存档于2015-12-18). 

外部链接