cover

MVC 就是把「資料」「畫面」「流程控制」拆開來,讓每個人只管自己的事。聽起來很基本,但你知道有多少專案是把三件事全部塞在同一個檔案裡嗎?

先講結論

MVC 的核心精神是關注點分離。Model 管資料和商業邏輯、View 管使用者介面、Controller 管流程協調。這個架構模式從 1970 年代就存在了,到今天它的變體(MVP、MVVM、Flux)仍然在主宰軟體開發。不是因為它完美,而是因為「把職責拆開」這件事本身就是對的。

用餐廳來理解 MVC

走進一間餐廳:菜單(View) 是你看到的東西,廚房(Model) 負責食材和料理邏輯,服務生(Controller) 接收你的點單、把需求傳給廚房、再把做好的菜端到你面前。

你不會自己跑進廚房炒菜,廚房也不需要知道菜單長什麼樣——每個角色各司其職。

使用者 ──請求──> Controller ──操作──> Model
  ↑                                    │
  └────回應──── View <──取得資料────────┘

實際的 code 長怎樣

以 Express.js 為例:

Model(處理資料)

// models/user.js
export const User = {
  async findById(id) {
    return db.query('SELECT * FROM users WHERE id = ?', [id]);
  },
  async create({ name, email }) {
    return db.query('INSERT INTO users (name, email) VALUES (?, ?)', [name, email]);
  },
};

Controller(處理流程)

// controllers/userController.js
export const userController = {
  async show(req, res) {
    const user = await User.findById(req.params.id);
    if (!user) return res.status(404).render('error', { message: '找不到' });
    res.render('user/show', { user });
  },
  async create(req, res) {
    if (!req.body.name || !req.body.email) {
      return res.status(400).render('user/new', { error: '請填完' });
    }
    const user = await User.create(req.body);
    res.redirect(`/users/${user.id}`);
  },
};

View(顯示畫面)

<!-- views/user/show.ejs -->
<h1><%= user.name %></h1>
<p>Email: <%= user.email %></p>

看到了嗎?Model 不知道畫面長什麼樣,View 不知道資料從哪來,Controller 負責把兩邊串起來。改 UI 不影響商業邏輯,改資料庫不影響畫面——這就是關注點分離的好處。

MVC 的真正問題:Fat Controller

理論講起來很美好,但實務上最常見的問題是 Controller 越長越肥。驗證邏輯放 Controller、商業規則放 Controller、權限檢查放 Controller、email 通知放 Controller——最後 Controller 變成一個什麼都管的巨獸。

解法?加一層 Service Layer

// Controller 只負責接收和回應
async create(req, res) {
  const result = await userService.register(req.body);
  if (result.error) return res.status(400).json({ error: result.error });
  res.status(201).json(result.user);
}

把商業邏輯抽到 Service,Controller 回歸它的本分:接收請求、呼叫 Service、回傳結果。

Web MVC 不是原本的 MVC

一個你可能不知道的事:現在 Web 框架裡的 MVC 跟 1970 年代 Smalltalk 的 MVC 其實不太一樣。

原始 MVC 裡,View 會直接監聽 Model 的變化(Observer Pattern),Controller 只處理使用者輸入。但 Web 是 Request-Response 模式——使用者發請求、伺服器回應、結束——不存在「View 持續監聽 Model」這回事。

所以嚴格來說,Web MVC 是一個「借用 MVC 精神但實作不同」的變體。不過名字已經叫習慣了,大家也就不計較了。

現代框架已經超越 MVC

React、Vue 這些框架用的是 Component-based 架構——View 和部分邏輯合在元件中,狀態用 Redux / Pinia 管理,API 前後端分離。已經不是傳統 MVC 了。

但 MVC 的核心精神——關注點分離——依然活著。不管架構怎麼演進,「把不同職責拆開」這個原則不會過時。

模式說明常見框架
MVC經典Rails, Laravel, Spring MVC
MVPPresenter 取代 ControllerAndroid(早期)
MVVMViewModel 與 View 雙向綁定Vue.js, Angular
Flux/Redux單向資料流React + Redux

MVC 不是銀彈,但它教會了我們一件事:把東西拆開來管,永遠比全部混在一起好。


延伸閱讀

MVC是一個巨大誤會 跟著小明一起搞懂技術名詞:MVC、SPA 與 SSR 架構 後端 MVP 設計原則 前端 MVP 設計原則