MVC 架构模式解析
MVC 架构模式
核心定义
MVC 是一种将应用拆分为三部分的架构模式:
- Model(模型):管理数据和业务逻辑
- View(视图):负责界面展示
- Controller(控制器):接收用户输入,协调 Model 和 View
通信规则
用户操作 → View → Controller → Model → View
三条铁律:
- View 不能直接调用 Model(必须通过 Controller)
- Model 不能直接操作 DOM(只能通知 View 去 render)
- Controller 不能直接操作 DOM(只能通过 View.render)
职责分离的本质
MVC 不是为了写更少的代码,而是为了改代码时只动一个文件。
| 需求变更类型 | 只需要改哪里 |
|---|---|
| 按钮样式、布局调整 | 只改 View |
| 业务流程判断(如权限校验) | 只改 Controller |
| 数据存储、校验规则 | 只改 Model |
完整代码示例
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MVC Demo</title>
</head>
<body>
<div class="app">
<div class="num">0</div>
<div>
<button id="add">+</button>
<button id="sub">-</button>
</div>
</div>
<script>
// ==================== Model 层 ====================
// 职责:存数据、改数据、管理监听者、发布通知
// 特点:完全不知道 DOM 和 Controller 的存在
class Model {
constructor() {
let count = 0;
this.add = function () {
count++;
return count;
};
this.sub = function () {
count--;
return count;
};
this.getValue = function () {
return count;
};
const views = [];
this.registry = function (view) {
views.push(view);
};
this.notify = function () {
views.forEach((view) => view.render(this));
};
}
}
// ==================== View 层 ====================
// 职责:展示数据、绑定 DOM 事件、持有 Controller 引用
// 特点:不知道数据怎么变的,只负责渲染和转发用户操作
class View {
constructor(controller) {
this.eleNum = document.querySelector('.num');
this.btnAdd = document.querySelector('#add');
this.btnSub = document.querySelector('#sub');
this.btnAdd.addEventListener('click', function () {
controller.add();
});
this.btnSub.addEventListener('click', function () {
controller.sub();
});
}
render(model) {
this.eleNum.innerHTML = model.getValue();
}
}
// ==================== Controller 层 ====================
// 职责:初始化应用、协调 Model 和 View、处理业务决策
// 特点:它是大脑,知道 Model 和 View 的存在,但不碰 DOM
class Controller {
constructor() {
this.model = new Model();
this.view = new View(this);
this.model.registry(this.view);
this.view.render(this.model);
}
add() {
this.model.add();
this.model.notify();
}
sub() {
this.model.sub();
this.model.notify();
}
}
// 启动应用
new Controller();
</script>
</body>
</html>
两种 MVC 变种
| 类型 | 更新触发方式 | 适用场景 |
|---|---|---|
| 被动模型(Passive Model) | Controller 手动调用 View.render() | 流程清晰、易调试 |
| 主动模型(Active Model) | Model 通过观察者模式自动通知 View | 自动化程度高 |
本例采用的是主动模型:Model 内部维护观察者列表,数据变化时通过 notify() 通知所有注册的 View。
关键设计细节
- Model 数据私有化:
count定义为构造函数内部的局部变量,外部只能通过暴露的方法访问,确保数据修改可控 - View 持有 Controller 引用:通过构造函数传入,View 只负责转发事件,不处理业务逻辑
- 观察者模式:
registry注册、notify广播,实现 Model 和 View 的松散耦合
React 与 MVC 的关系
React 官方定位是 View 层库,只负责 UI 渲染。在实际开发中:
- 组件内部的
state承担了部分 Model 职责 - 事件处理函数承担了 Controller 职责
- JSX 承担了 View 职责
React 没有严格的 Controller 层,逻辑和视图更容易混在一起,需要配合状态管理库或自定义 Hooks 来保持清晰的职责分离。