MVC 起源與核心哲學
MVC (Model-View-Controller) 起源於 Smalltalk-80 系統,是**使用者介面架構的經典模式**。核心哲學:**關注點分離**——將應用程式拆解為三個獨立角色,降低耦合,提升彈性與可重用性。
三大角色職責
| 角色 | 職責 | 關鍵特性 |
| Model (模型) | 封裝業務邏輯、資料與狀態。不包含任何 UI 邏輯。 | 可被多個 View 共享;狀態變更通知 View |
| View (視圖) | 呈現 Model 資料的視覺化表示。負責渲染、佈局、使用者互動元素。 | 可巢狀組合 (Composite);對 Model 變更做反應 (Observer) |
| Controller (控制器) | 處理使用者輸入 (點擊、鍵盤、表單提交),轉換為 Model 操作或 View 切換。 | 可動態替換策略 (Strategy);封裝輸入處理算法 |
MVC 協作流程
- 使用者透過 View 進行操作 (點擊按鈕、提交表單)
- View 將事件委派給 Controller
- Controller 解析輸入,呼叫 Model 业務方法 (更新狀態)
- Model 狀態變更,觸發 **Observer 模式** 通知所有註冊的 View
- View 收到通知,從 Model 取得最新資料,重新渲染

MVC 中的三大核心設計模式
1. Observer 模式 (觀察者模式) —— Model ↔ View 解耦
- **主題 (Subject)**:Model,維護觀察者清單,狀態變更時 `notifyObservers()`
- **觀察者 (Observer)**:View,實作 `update()` 介面,收到通知後重繪
- **效果**:Model 完全不知 View 存在,View 可動態增減,支援**一個 Model 對多個 View** (如同步顯示圖表、表格、文字)
2. Composite 模式 (組合模式) —— View 巢狀結構
- **元件介面 (Component)**:`View`,定義 `render()`、`addChild()`、`removeChild()`
- **葉節點 (Leaf)**:基本 UI 元素 (Button、Label、TextField)
- **合成節點 (Composite)**:容器 (Panel、Form、Dialog),持有子 View 集合
- **效果**:統一介面處理單一元素與容器,**遞迴渲染**,支援任意深度巢狀
3. Strategy 模式 (策略模式) —— Controller 可換行為
- **策略介面 (Strategy)**:`Controller`,定義 `handleInput(event)`
- **具體策略**:`KeyboardController`、`MouseController`、`TouchController`、`PopupMenuController`
- **效果**:View 執行期可動態替換 Controller,**不修改 View 代碼即可改變互動行為** (如啟用/停用、切換鍵盤/滑鼠/觸控模式)
其他輔助模式
- Factory Method:View 建立預設 Controller (如 `createDefaultController()`)
- Decorator:為 View 動態增加職責 (如捲動條、邊框、陰影),不改變核心渲染邏輯
Web 應用中的 MVC (Model 2 架構)
經典 MVC 為桌面應用設計 (同進程)。Web 應用採用 **Model 2** 變體:
| 桌面 MVC | Web Model 2 |
| View 直接觀察 Model | View (JSP) 從 Request 屬性讀取資料,不直接觀察 Model |
| Controller 為物件 | Controller 為 Servlet/Action,無狀態、多執行緒共用 |
| 同步通知 | Request-Response 週期,Controller 執行完轉發至 View |
Struts 1.x 架構解析 (經典 Model 2 實現)
核心組件
- ActionServlet (Front Controller):單一進入點,接收所有請求,委派給 RequestProcessor
- RequestProcessor:處理請求生命週期 (找 Action、表單驗證、執行 Action、轉發 View)
- ActionForm (Form Bean):封裝請求參數,提供驗證 (`validate()`)、重置 (`reset()`)
- Action:業務邏輯入口,`execute()` 回傳 `ActionForward` 指定下一個 View
- ActionForward:封裝轉發目標 (路徑、重導向標記)
- struts-config.xml:集中配置 Action 映射、Form Bean、Forward、全域設定
請求處理流程
- 瀏覽器請求 `*.do` → `ActionServlet` (web.xml 映射)
- `RequestProcessor` 依 `path` 找到 `` 配置
- 若配置 ``,實例化/取得 `ActionForm`,自動填充請求參數
- 呼叫 `form.validate()`,失敗則轉發回 `input` 頁面顯示錯誤
- 實例化 `Action`,呼叫 `execute(mapping, form, request, response)`
- `Action` 執行業務邏輯 (呼叫 Service/DAO),將結果放入 `request`/`session`
- `Action` 回傳 `ActionForward` (如 `mapping.findForward("success")`)
- `RequestProcessor` 依 `Forward` 轉發至 JSP (View)
- JSP 使用 ``、`` 等標籤庫渲染 Model 資料
Struts 核心優勢 (歷史視角)
- **標準化 Web MVC**:早期 JSP/Servlet 亂象中建立規範
- **集中配置**:`struts-config.xml` 統一管理導航、驗證、國際化
- **表單處理框架**:`ActionForm` 自動綁定、驗證、錯誤回顯
- **標籤庫豐富**:HTML、Logic、Bean、Tiles 標籤簡化 JSP 開發
- **擴展點完整**:RequestProcessor、ActionServlet、PlugIn 可客製化
Struts 核心痛點 (導致後續框架演進)
- **ActionForm 繁瑤**:每個表單需寫 Form Bean,Getter/Setter、validate、reset 樣板代碼多
- **配置地獄**:大型專案 `struts-config.xml` 動輒數千行,維護困難
- **非 POJO**:`Action` 需繼承基類,`execute()` 簽名固定,難以單元測試
- **Thread 安全**:`Action` 實例單例共用,成員變數需極度小心
- **前端綁死**:強依賴 JSP 標籤庫,難以支援 AJAX/REST/前後端分離
從 Struts 到現代框架的演進
| 框架 | 核心改進 | MVC 定位 |
| Struts 1 | Front Controller、配置驅動、Form Bean | Model 2 奠基者 |
| WebWork / Struts 2 | 攔截器鏈、OGNL 表達式、POJO Action、AOP 支援 | Action 變 POJO,攔截器替代繼承 |
| Spring MVC | DispatcherServlet、@Controller、@RequestMapping、靈活綁定、REST 原生支援 | 企業級標準,與 Spring 生態無縫整合 |
| Spring Boot + Spring MVC | 零配置、內嵌容器、Starter 依賴、Actuator 監控 | 微服務時代首選 |
總結:MVC 精神不變,形式隨時代演進
- 核心不變:Model (資料/業務)、View (呈現)、Controller (協調) 三者分離
- Observer 解耦 Model-View → 現代框架用事件總線/Reactive Streams 實現
- Composite 組合 View → 現代前端框架 (React/Vue/Angular) 組件樹完美體現
- Strategy 切換 Controller 行為 → 現代攔截器/Filter/Aspect 更靈活
- Struts 歷史使命:在 JSP/Servlet 時代建立 Web MVC 規範,雖已退場,其設計思想深刻影響後續所有 Java Web 框架
理解 MVC 本質與 Struts 實現細節,不僅是考古,更是為了掌握**架構演進的邏輯主線**,在技術選型與系統設計時做出更有洞見的決策。