模型-视图-控制器

**MVC 模式**（Model–view–controller）是軟體工程中的一種軟體架構模式，把軟體系統分為三個基本部分：模型（Model）、視圖（View）和控制器（Controller）。

MVC 模式最早由 Trygve Reenskaug 在 1978 年提出，是全錄帕羅奧多研究中心（Xerox PARC）在 20 世紀 80 年代為程式語言 Smalltalk 發明的一種軟體架構。**MVC 模式**的目的是實現一種動態的程式設計，使後續對程式的修改和擴充簡化，並且使程式某一部分的重複利用成為可能。除此之外，此模式透過對複雜度的簡化，使程式結構更加直覺。軟體系統透過對自身基本部分分離的同時也賦予了各個基本部分應有的功能。專業人員可以依據自身的專長分組：

* 模型（Model） - 程式設計師編寫程式應有的功能（實現演算法等等）、資料庫專家進行資料管理和資料庫設計 (可以實現具體的功能)。
* 視圖（View） - 介面設計人員進行圖形介面設計。
* 控制器（Controller）- 負責轉發請求，對請求進行處理。

## 組件的互動

將應用程式劃分為三種組件，模型 - 視圖 - 控制器（MVC）設計定義它們之間的相互作用。

* **模型（Model）** 用於封裝與應用程式的業務邏輯相關的資料以及對資料的處理方法。「 Model 」有對資料直接存取的權力，例如對資料庫的存取。「Model」不依賴「View」和「Controller」，也就是說， Model 不關心它會被如何顯示或是如何被操作。但是 Model 中資料的變化一般會通過一種重新整理機制被公布。為了實現這種機制，那些用於監視此 Model 的 View 必須事先在此 Model 上註冊，從而，View 可以了解在資料 Model 上發生的改變。（比如：觀察者模式）
* **視圖（View）** 能夠實現資料有目的的顯示（理論上，這不是必需的）。在 View 中一般沒有程式上的邏輯。為了實現 View 上的重新整理功能，View 需要存取它監視的資料模型（Model），因此應該事先在被它監視的資料那裡註冊。
* **控制器（Controller）** 起到不同層面間的組織作用，用於控制應用程式的流程。它處理事件並作出回應。「事件」包括使用者的行為和資料 Model 上的改變。

## 優點

在最初的 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 三個部份分離實作：

* Model 負責資料存取，較現代的 Framework 都會建議使用獨立的資料物件 (DTO, POCO, POJO 等) 來替代弱型別的集合物件。資料存取的程式碼會使用 Data Access 的程式碼或是 ORM-based Framework，也可以進一步使用 Repository Pattern 與 Unit of Works Pattern 來切割資料來源的相依性。
* Controller 負責處理訊息，較高階的 Framework 會有一個預設的實作來作為 Controller 的基礎，例如 Spring 的 DispatcherServlet 或是 ASP.NET MVC 的 Controller 等，在職責分離原則的基礎上，每個 Controller 負責的部份不同，因此會將各個 Controller 切割成不同的檔案以利維護。
* View 負責顯示資料，這個部份多為前端應用，而 Controller 會有一個機制將處理的結果 (可能是 Model, 集合或是狀態等) 交給 View，然後由 View 來決定怎麼顯示。例如 Spring Framework 使用 JSP 或相應技術，ASP.NET MVC 則使用 Razor 處理資料的顯示。

也因為 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 不是一種技術，而是一種理念。

在這個簡短的程式中就是一個完整的 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 來撰寫外，亦可用其他框架來撰寫，常見的有 Struts2、Spring 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。

在 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 架構。最常用的有 Django 和 TurboGears。

### JavaScript

* Backbone.js
* Angular.js
* Ember.js （頁面存檔備份，存於網際網路檔案館）
* JavaScriptMVC
* Model-View-Controller (MVC) with JavaScript

### PHP

* CakePHP （頁面存檔備份，存於網際網路檔案館）
* CodeIgniter （頁面存檔備份，存於網際網路檔案館）
* prado
* symfony （頁面存檔備份，存於網際網路檔案館）
* Yii Framework （頁面存檔備份，存於網際網路檔案館）
* Zend Framework （頁面存檔備份，存於網際網路檔案館）
* Phalcon （頁面存檔備份，存於網際網路檔案館）
* Laravel （頁面存檔備份，存於網際網路檔案館）
* ThinkPHP

### ActionScript 3

* PureMVC Standard for ActionScript 3

## 參考

* JSP model 2 architecture

## 參考文獻

## 外部連結

* An overview of the MVC pattern in Java from the Sun website （頁面存檔備份，存於網際網路檔案館）
* Model View Presenter with ASP.NET CodeProject article.
* History of the evolution of MVC and derivatives （頁面存檔備份，存於網際網路檔案館） by Martin Fowler.
* ASP.NET MVC Framework （頁面存檔備份，存於網際網路檔案館） Microsoft's Scott Guthrie on .NET MVC
* Introduction to the ASP.NET Model View Controller (MVC) Framework Scott Hanselman builds an application step-by-step using the first CTP of the ASP.NET MVC Framework in this Introductory Video
* Holub, Allen. Building user interfaces for object-oriented systems. Java World. 1999 [2009-07-19]. （原始內容存檔於 2005-11-02）.
* Greer, Derek. "Interactive Application Architecture Patterns", Ctrl-Shift-B, 2007.
* Building Graphical User Interfaces with the MVC Pattern in Java （頁面存檔備份，存於網際網路檔案館）