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 的運作流程
-
使用者在 View 上進行操作(例如點擊按鈕)。
-
Controller 接收到使用者的輸入,根據邏輯更新 Model。
-
Model 更新後,通知 View 重新渲染。
-
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 的運作流程
-
View 顯示資料,這些資料來自 ViewModel。
-
使用者在 View 上操作,View 透過雙向綁定直接更新 ViewModel。
-
ViewModel 更新 Model 的資料(如果需要與後端同步)。
-
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)解決大型應用程式的資料管理問題。
-