網站在過去 20 年間,從簡單的 HTML 頁面加一點 CSS,演變成了功能非常多的應用程式。
功能一多,程式碼量就會變得非常龐大,通常需要好幾個開發者一起協作。
但當好幾個人同時在寫同一個專案,如果沒有一套整理的規則,每個人會把程式碼放在不同的地方,用不同的寫法。
舉個例子,假設三個人一起開發一個購物網站:
- 小明把「會員登入」的程式碼放在一個叫
tools.js的檔案裡。 - 小華把「購物車」的程式碼也放在
tools.js裡面,但放在最底下。 - 小美把「結帳」的程式碼放在另一個叫
helpers.js的檔案裡。
三個月後,老闆說登入功能要改。
但小明已經離職了,接手的人打開專案,根本不知道登入的程式碼在哪個檔案裡。
好不容易在 tools.js 裡找到了,改完之後,購物車卻突然壞掉了——因為小華的購物車程式碼剛好也在同一個檔案裡,而且偷偷用了登入的某段程式碼。
光是找出問題在哪,就花了一整天。
所以開發者們需要一套方法來整理程式碼。
MVC 就是目前最受歡迎的一種整理程式碼的方法,全名是 Model-View-Controller(模型-視圖-控制器)。
接下來,我們就用這個購物網站的例子,帶你搞懂 MVC 到底是怎麼整理程式碼的。
MVC 的核心概念:把程式碼分成三塊
MVC 的目標很單純:把一個大型應用程式,拆分成三個各司其職的區塊。
這三個區塊分別是:
- Model(模型):負責處理資料,例如跟資料庫溝通、儲存、更新、刪除資料。
- View(視圖):負責呈現畫面,把資料排版成使用者看到的網頁。
- Controller(控制器):負責協調 Model 和 View,接收使用者的請求後,叫 Model 去拿資料,再交給 View 顯示。
一個請求在 MVC 裡的完整流程
讓我們來看看使用者發出請求後,MVC 是怎麼運作的。
整個流程可以用這張圖來理解:
graph LR
A[使用者] -->|1.發出請求| B[Controller]
B -->|2.跟 Model 要資料| C[Model]
C -->|3.從資料庫拿資料| D[(資料庫)]
D -->|4.回傳資料| C
C -->|5.回傳資料| B
B -->|6.把資料交給 View| E[View]
E -->|7.回傳 HTML 畫面| B
B -->|8.回傳畫面| A接下來一步一步拆解。
第一步:使用者發出請求
假設使用者在瀏覽器輸入了一個網址,想要看某個頁面。
這個請求會送到伺服器。
第二步:Controller 接收請求
伺服器會根據網址,把請求交給負責的 Controller。
一個網站裡通常會有很多個 Controller,每個 Controller 負責不同的功能。
伺服器會看網址是跟哪個功能有關,就交給哪個 Controller 來處理。
例如一個購物網站可能會有:負責商品的 Controller、負責會員的 Controller、負責訂單的 Controller。
Controller 就像一個中間人,它的職責是「指揮」其他兩個區塊該做什麼。
重點是:Controller 本身不應該包含太多程式碼,它只負責協調。
第三步:Controller 向 Model 要資料
Controller 收到請求後,第一件事就是去問 Model:「我需要這些資料,幫我處理一下。」
Model 負責所有跟資料有關的事情,包括:跟資料庫溝通、驗證資料、儲存資料、更新資料、刪除資料。
Controller 絕對不會直接碰資料庫,所有跟資料有關的操作,都必須透過 Model 來進行。
這樣做的好處是:Controller 不需要煩惱「資料該怎麼處理」,它只要告訴 Model「我要什麼」就好。
反過來,Model 也不需要管「使用者的請求長什麼樣」或「請求失敗要怎麼辦」,這些都是 Controller 的事。
第四步:Model 回傳資料給 Controller
Model 從資料庫拿到資料後,會把結果回傳給 Controller。
第五步:Controller 把資料交給 View
Controller 拿到資料後,接著要請 View 把資料變成使用者看得懂的畫面。
View 就是一個模板檔案,它會根據 Controller 傳來的資料,動態產生 HTML。
View 只關心一件事:怎麼把資料漂亮地呈現出來。
它不管資料是怎麼來的,也不管最終要怎麼回傳給使用者。
第六步:View 回傳畫面,Controller 送回給使用者
View 產生好 HTML 後,會把結果交回 Controller。
Controller 再把這個最終的畫面,回傳給使用者的瀏覽器。
整個流程就完成了。
MVC 最重要的設計原則:Model 和 View 不直接溝通
在 MVC 裡面,有一個非常關鍵的規則:Model 和 View 之間絕對不會直接互動。
什麼意思呢?
Model 不會自己把資料丟給 View,View 也不會自己跑去跟 Model 要資料。
所有的資料傳遞,都必須經過 Controller。
也就是說,資料的流向永遠是:Model → Controller → View,反過來也是 View → Controller → Model。
Controller 就是中間那個必經的關卡,所有資料都要經過它。
這個設計帶來一個很重要的好處:處理資料的程式碼和顯示畫面的程式碼被完全分開了。
因為 Model 和 View 之間沒有任何直接的關聯,所以你改了 View 的程式碼,Model 不會受到影響。
改了 Model 的程式碼,View 也不會壞掉。
還記得前言裡小華改了登入功能結果購物車壞掉的情況嗎?那就是因為程式碼全部混在一起,改了 A 就連帶影響 B。
MVC 透過「所有資料都必須經過 Controller」這個規則,讓每一塊程式碼只管自己的事,互相不干擾。
這就是為什麼 MVC 能讓複雜的應用程式變得更好管理。
用購物網站走一次 MVC 完整流程
把前面學到的觀念串起來,完整走一次流程。
情境:使用者想要查看購物網站上的商品列表。
正常流程
- 使用者在瀏覽器輸入商品列表的網址。
- 伺服器把請求交給「負責商品的 Controller」。
- Controller 請「負責商品的 Model」去資料庫查詢所有商品的資料。
- Model 從資料庫拿到商品列表(名稱、價格、圖片等),回傳給 Controller。
- Controller 確認資料沒問題,把商品列表交給「負責商品的 View」。
- View 把商品列表排版成漂亮的 HTML 頁面,交回 Controller。
- Controller 把這個頁面回傳給使用者。
使用者就看到了一頁漂亮的商品列表。
錯誤流程
但如果 Model 在查詢資料庫時發生錯誤呢?
- Model 回傳的不是商品列表,而是一個錯誤訊息。
- Controller 收到錯誤後,不會去找「商品的 View」,而是改找「負責錯誤畫面的 View」。
- 錯誤的 View 產生一個錯誤提示頁面,交回 Controller。
- Controller 把錯誤頁面回傳給使用者。
這就是 Controller 身為「中間人」的價值:它能根據不同的情況,決定要用哪個 View 來呈現結果。
MVC 是一種設計原則,不是固定的寫法
前面的範例都是用「購物網站」來說明 MVC,所以文章裡的 Model 都在連資料庫,View 都在產生 HTML 畫面。
但 MVC 並不是只能用在網站開發上。
它的核心其實是一個很簡單的整理原則:把程式碼按照「資料處理」、「畫面呈現」、「流程控制」三種職責分開放。
至於每一塊具體在做什麼,會隨著你開發的東西不同而改變。
Model 不一定是連資料庫
在購物網站的例子裡,Model 是去資料庫查商品資料。
但 Model 真正的職責是「負責處理資料的來源和邏輯」,資料庫只是其中一種資料來源。
如果你的資料不是存在自己的資料庫裡呢?
例如你在做一個天氣 App,天氣資料是從氣象局的 API 拿回來的。
這時候 Model 做的事就是「呼叫氣象局的 API,把拿回來的資料整理好」,完全不需要碰資料庫。
又例如你在做一個讀取 CSV 檔案的小工具,Model 做的事就是「打開檔案,把裡面的資料解析出來」。
不管資料從哪裡來,只要是「跟資料打交道」的程式碼,都是 Model 的職責。
View 不一定是產生 HTML
在購物網站的例子裡,View 是把商品列表變成一個 HTML 網頁。
但 View 真正的職責是「負責把結果呈現給使用者」,HTML 只是其中一種呈現方式。
如果你在開發手機 App,View 就不是 HTML 了,而是手機螢幕上的畫面元件,像是按鈕、列表、彈窗。
如果你在寫一個給其他程式使用的 API,根本沒有「畫面」這個概念。
這時候 View 做的事可能只是把資料整理成一段 JSON 格式回傳,讓其他程式可以讀取。
不管最終的呈現方式是什麼,只要是「把結果展示出去」的程式碼,都是 View 的職責。
Controller 不一定是接收網址請求
在購物網站的例子裡,Controller 是接收使用者輸入的網址,然後去協調 Model 和 View。
但 Controller 真正的職責是「接收使用者的輸入,然後決定要叫誰做什麼事」。
使用者的輸入不一定是網址。
在手機 App 裡,使用者的輸入可能是「按了一個按鈕」或「滑了一下螢幕」。
在桌面程式裡,使用者的輸入可能是「點了選單裡的某個選項」。
不管輸入從哪裡來,只要是「接收輸入,然後協調 Model 和 View」的程式碼,都是 Controller 的職責。
重點是職責分離
所以不要把 MVC 想成「一定要怎麼寫」,而是把它想成一種整理程式碼的思維方式。
不管你在做網站、手機 App、桌面程式,還是任何類型的專案,只要把程式碼按照這三種職責分開,每一塊只管自己的事,專案就會更好維護。
MVC 重點整理
MVC 的核心觀念其實很簡單,就是把程式碼拆成三個角色:
- Model(模型):處理所有跟資料有關的邏輯,跟資料庫溝通、驗證、儲存、更新、刪除。
- View(視圖):負責畫面呈現,把資料轉成使用者看得懂的 HTML。
- Controller(控制器):負責協調,接收使用者請求後,指揮 Model 和 View 各做各的事。
最關鍵的設計原則是:Model 和 View 不直接溝通,所有互動都透過 Controller。
回想一開始購物網站的例子,小明、小華、小美各寫各的,程式碼全混在一起,改一個地方就壞另一個。
如果用 MVC 來整理,資料邏輯放 Model、畫面放 View、協調放 Controller,每個人負責的範圍很清楚,就不會互相影響了。