Skip to main content

MVC、MVVM介紹,以及當代框架的解決之道

一、MVC 介紹

1.1 什麼是 MVC?

MVC(Model-View-Controller)是一種軟體設計模式,廣泛應用於應用程式開發,特別是在 Web 開發中。它的核心思想是將應用程式的邏輯分為三個部分,以提高程式碼的可維護性和可擴展性:

  • Model(模型):負責管理資料和業務邏輯,與後端 API 或資料庫互動,處理資料的儲存、檢索和更新。例如,Model 可能包含使用者的資料結構和操作資料的方法。

  • View(視圖):負責顯示資料給使用者,是使用者與應用程式互動的介面。View 通常只呈現資料,不處理業務邏輯。

  • Controller(控制器):負責處理使用者的輸入,作為 Model 和 View 之間的橋樑。Controller 會接收使用者的動作(例如點擊按鈕),更新 Model,並通知 View 重新渲染。

1.2 MVC 的運作流程

  1. 使用者在 View 上進行操作(例如點擊按鈕)。

  2. Controller 接收到使用者的輸入,根據邏輯更新 Model。

  3. Model 更新後,通知 View 重新渲染。

  4. View 從 Model 取得最新的資料,更新畫面。

1.3 MVC 的優缺點

優點

  • 分離關注點(Separation of Concerns),Model、View、Controller 各司其職,程式碼結構清晰。

  • 易於維護和測試,因為每個部分的職責明確。

  • 適用於傳統的 Web 應用程式(如伺服器端渲染的框架)。

缺點

  • 在前端應用程式中,Controller 可能變得過於複雜,特別是當應用程式規模變大時。

  • View 和 Model 之間的耦合度可能較高,導致難以獨立修改。

  • 在現代前端開發中,MVC 的結構可能不夠靈活,難以應對複雜的互動式 UI。

二、MVVM 介紹

2.1 什麼是 MVVM?

MVVM(Model-View-ViewModel)是一種改良自 MVC 的設計模式,特別適合現代前端框架(如 Vue.js、Angular)。它將 Controller 替換為 ViewModel,強調資料的雙向綁定(Data Binding)。

  • Model:與 MVC 的 Model 類似,負責資料和業務邏輯。

  • View:負責顯示 UI,與 MVC 的 View 相同,但通常透過資料綁定與 ViewModel 互動。

  • ViewModel:負責將 Model 的資料轉換為 View 可以直接使用的格式,並處理使用者輸入。ViewModel 通常會提供資料的「可觀察」(Observable)屬性,當資料變化時,View 會自動更新。

2.2 MVVM 的運作流程

  1. View 顯示資料,這些資料來自 ViewModel。

  2. 使用者在 View 上操作,View 透過雙向綁定直接更新 ViewModel。

  3. ViewModel 更新 Model 的資料(如果需要與後端同步)。

  4. Model 資料變化時,通知 ViewModel,ViewModel 再通知 View 重新渲染。

2.3 MVVM 的優缺點

優點

  • 雙向綁定:View 和 ViewModel 之間的資料同步簡化了開發流程。

  • 適合複雜的互動式 UI,因為 ViewModel 減少了直接操作 DOM 的需求。

  • ViewModel 讓資料邏輯和 UI 邏輯分離,提高可維護性。

缺點

  • ViewModel 可能變得過於複雜,特別是在大型應用程式中。

  • 雙向綁定可能導致效能問題,特別是當資料量很大時。

  • 學習曲線較高,特別是需要用到可觀察物件(Observable)或資料綁定框架。

三、當代框架的解決之道

現代前端框架(如 React、Vue.js、Angular)針對 MVC 和 MVVM 的缺點提出了改進,並結合了新的設計理念來應對複雜的前端應用需求。以下以 React 為例,說明當代框架如何解決 MVC 和 MVVM 的問題:

3.1 React 的組件化設計

React 的核心是組件化(Component-Based Architecture),將 UI 分成獨立的組件,每個組件可以獨立管理自己的狀態和邏輯。這種方式解決了 MVC 和 MVVM 的以下問題:

  • 問題:MVC 的 Controller 和 MVVM 的 ViewModel 可能變得過於複雜。

  • React 解決方案:每個組件負責自己的邏輯和狀態,減少單一控制層的負擔。例如,useState 和 useReducer Hook 讓狀態管理更加模組化。

function Counter() {
const [count, setCount] = React.useState(0);

return (
<div>
<p>計數:{count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
);
}

3.2 單向資料流

React 採用單向資料流(Unidirectional Data Flow),避免了 MVVM 雙向綁定可能帶來的效能問題和複雜性。父組件傳遞資料(props)給子組件,子組件透過回呼函數(callback)通知父組件更新狀態。

解決方案

  • 單向資料流讓資料流動更可預測,減少除錯難度。

  • 使用 useState 或 Redux 等工具來集中管理狀態,確保資料一致性。

function Parent() {
const [count, setCount] = React.useState(0);

return <Child count={count} onIncrement={() => setCount(count + 1)} />;
}

function Child({ count, onIncrement }) {
return (
<div>
<p>計數:{count}</p>
<button onClick={onIncrement}>增加</button>
</div>
);
}

3.3 狀態管理工具

對於大型應用程式,React 提供了狀態管理工具(如 Redux、MobX、Zustand)來解決 MVC 和 MVVM 中 Model 層的複雜性問題。

  • Redux:集中式狀態管理,將所有資料儲存在一個全局 Store 中,適合大型應用程式。

  • MobX:提供可觀察物件,模擬 MVVM 的雙向綁定,適合需要快速開發的場景。

  • Zustand:輕量級狀態管理,簡單易用,適合中小型專案。

範例(使用 Redux)

import { createSlice, configureStore } from "@reduxjs/toolkit";
import { Provider, useDispatch, useSelector } from "react-redux";

// Model: Redux Slice
const todoSlice = createSlice({
name: "todos",
initialState: {
todos: [],
},
reducers: {
addTodo: (state, action) => {
state.todos.push({
id: Date.now(),
text: action.payload,
completed: false,
});
},
toggleTodo: (state, action) => {
const todo = state.todos.find((todo) => todo.id === action.payload);
if (todo) {
todo.completed = !todo.completed;
}
},
},
});

const store = configureStore({
reducer: {
todos: todoSlice.reducer,
},
});

const { addTodo, toggleTodo } = todoSlice.actions;

// View
function TodoList() {
const todos = useSelector((state) => state.todos.todos);
const dispatch = useDispatch();
const [input, setInput] = React.useState("");

return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="輸入待辦事項"
/>
<button
onClick={() => {
dispatch(addTodo(input));
setInput("");
}}
>
新增
</button>
<ul>
{todos.map((todo) => (
<li
key={todo.id}
style={{ textDecoration: todo.completed ? "line-through" : "none" }}
onClick={() => dispatch(toggleTodo(todo.id))}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}

// 整合
function App() {
return (
<Provider store={store}>
<h1>待辦事項清單</h1>
<TodoList />
</Provider>
);
}

export default App;

3.4 虛擬 DOM 和高效渲染

React 的虛擬 DOM 解決了 MVC 和 MVVM 中頻繁操作真實 DOM 導致的效能問題。React 會比較虛擬 DOM 的變化,只更新必要的部分,從而提高渲染效率。

3.5 Hook 的靈活性

React Hook(如 useState、useEffect、useReducer)讓開發者可以靈活地在組件中管理狀態和副作用,無需依賴複雜的 Controller 或 ViewModel。


四、總結

  • MVC:適合結構化的應用程式,但 Controller 可能變得複雜,耦合度較高。

  • MVVM:透過雙向綁定簡化開發,但可能帶來效能問題和 ViewModel 的複雜性。

  • React 的解決之道

    • 組件化設計讓程式碼模組化,減少耦合。

    • 單向資料流提高資料可預測性。

    • 狀態管理工具(如 Redux)解決大型應用程式的資料管理問題。