January 23, 2026 (3mo ago)

模型-视图-控制器 图解实用指南

通过简单类比和真实示例理解模型-视图-控制器图。了解 MVC 如何组织代码以实现可扩展、可维护的软件。

← Back to blog
Cover Image for 模型-视图-控制器 图解实用指南

通过简单类比和真实示例理解模型-视图-控制器图。了解 MVC 如何组织代码以实现可扩展、可维护的软件。

A Model View Controller 图不仅仅是技术图纸;它是应用架构的蓝图。它展示了如何将复杂系统拆分为三个不同但相互关联的部分:Model(模型,数据和核心逻辑)、View(视图,用户所见)和 Controller(控制器,协调者)。这种分离使代码更可扩展、更易测试且更易维护。1

分解 MVC 架构模式

为了让该模式更具象,想象一家餐厅。

  • Model 是厨房:它保存原料(数据)和配方(业务规则)。
  • View 是菜单和餐桌布置:它向客人展示选项和成品菜肴。
  • Controller 是服务员:它从 View 接收订单,要求 Model 准备,并将结果返回给 View。

这种“关注点分离”是 MVC 的核心优势,有助于团队避免紧耦合的代码,这类代码难以更改或测试。2

在实践中,MVC 图充当一种共享语言,让开发者、产品经理和利益相关者就应用如何工作达成一致。清晰的图示能加快入职速度并减少团队间的误解。3

分解核心 MVC 组件

Model:操作的大脑

Model 管理数据、状态和业务规则。它是单一真相来源,不应了解诸如 HTML 或 CSS 之类的呈现细节。它的职责包括验证、持久化,以及向系统其他部分暴露所需的操作。

View:应用的面孔

View 的唯一工作是呈现。它从 Model(通常通过 Controller)接收数据,渲染 UI,并捕获用户交互。View 不应直接更改应用数据;它只应将用户操作通知 Controller。

Controller:交通指挥

Controller 解释用户输入、协调 Model 更新,并选择 View 应如何响应。保持控制器精简:应将繁重工作委托给模型或服务类,避免嵌入复杂的业务逻辑。

角色与职责(快速参考)

ComponentPrimary ResponsibilityCommon Pitfalls to Avoid
ModelManage data, enforce business rulesMixing in UI logic or rendering HTML
ViewRender data and capture inputMutating data or holding business logic
ControllerCoordinate input and model updatesPerforming heavy data processing or DB queries directly

MVC 如何处理用户请求——逐步说明

以典型的联系表单提交为例,观察 MVC 的运行:

  1. 用户与 View 交互(填写表单并点击“提交”)。
  2. View 将收集的输入通知 Controller。
  3. Controller 验证并将处理委托给 Model。
  4. Model 验证、保存数据并更新状态。
  5. View 重新渲染以显示新状态(例如,“感谢您的留言!”确认)。

这种单向流程减少了耦合,使得对系统的推理变得直观。阻止 View 与 Model 直接通信可以避免隐藏的依赖关系和“意大利面条式代码”。2

在现代代码中实践 MVC

典型的 Node.js + Express 后端配合 React 前端能很好地映射到 MVC。一个简单的文件夹结构是:

/project-root ├── /src │ ├── /controllers # 处理传入请求并协调响应 │ ├── /models # 管理数据和业务规则 │ └── /views_or_components # React 组件或服务器端视图

Example controller (TypeScript + Express):

// src/controllers/userController.ts
import { Request, Response } from 'express';
import { User } from '../models/userModel';

export const getUserProfile = (req: Request, res: Response) => {
  const userId = req.params.id;
  const user = User.findById(userId);

  if (user) {
    res.status(200).json(user);
  } else {
    res.status(404).send('User not found');
  }
};

Example model (conceptual):

// src/models/userModel.ts
const users = [
  { id: '1', name: 'Alex Doe', email: 'alex@example.com' },
  { id: '2', name: 'Jane Smith', email: 'jane@example.com' },
];

export class User {
  static findById(id: string) {
    return users.find(user => user.id === id);
  }
}

React component (View):

// src/components/UserProfile.tsx
import React, { useState, useEffect } from 'react';

const UserProfile = ({ userId }) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]);

  if (!user) return <div>Loading...</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
    </div>
  );
};

这种结构使每一层都更专注且易于测试,并帮助团队在不产生缠结依赖的情况下扩展代码库。有关 MVC 基础的更多内容,请参见 Codecademy 的概览。1

将 MVC 与其他设计模式比较

MVC 是经典模型,但根据 UI 复杂性和测试目标,MVP 或 MVVM 有时更合适。

  • MVP(Model–View–Presenter):Presenter 承担呈现逻辑并驱动被动的 View。在你想最大化 UI 可测试性时很有用。
  • MVVM(Model–View–ViewModel):ViewModel 暴露可绑定的数据和命令;View 将其绑定。由于数据绑定和响应式更新,该模式在现代 UI 框架中很受欢迎。5

每种模式都在不同的权衡中进行优化:分离与清晰(MVC)、可测试性(MVP)或 UI 响应性与减少样板代码(MVVM)。

常见的 MVC 错误及修复方法

即使有正确的 MVC 图示,团队也可能陷入会积累技术债务的反模式。

肥大控制器

当控制器包含业务逻辑、计算或直接的数据库工作时,它们会变得难以测试和重用。将复杂逻辑移入模型或专用服务类,让控制器作为协调者。

贫血模型

当模型仅包含数据而无行为时,业务规则会散落在控制器和服务中。将行为重新引入模型,使其负责自身的不变量和操作。Martin Fowler 对贫血领域模型的讨论很有帮助。4

避免让 View 与 Model 直接通信;所有交互应通过 Controller 流动,以保持清晰的关注点分离。2

常见问题解答 — 常见的 MVC 问题

在像 React 这样的框架下 MVC 仍然有用吗?

有用。React 覆盖了视图层,但你仍然需要一个放置应用状态和业务规则的地方(Model),以及将状态更改连接到 UI 的方式(Controller 或等价物)。将这些角色分开可以防止 React 组件变得臃肿。

团队在采用 MVC 时最常犯的错误是什么?

最常见的错误是创建肥大控制器。通过将验证和业务逻辑委托给模型或服务来保持控制器精简。

MVC 图如何帮助团队协作?

清晰的图示是共享蓝图。它减少了歧义,加速了入职,并让团队可以并行工作而不互相越权。


在 Clean Code Guy,我们帮助团队将这些原则应用于构建经久耐用的软件。访问我们的指南和服务: https://cleancodeguy.com

3.
GeeksforGeeks,“MVC 设计模式”,https://www.geeksforgeeks.org/mvc-design-pattern/
4.
Martin Fowler,“贫血领域模型”,https://martinfowler.com/bliki/AnemicDomainModel.html
5.
React 文档,“React – 用于构建用户界面的 JavaScript 库”,https://react.dev
← Back to blog
🙋🏻‍♂️

AI编写代码。
您让它持久。

在AI加速的时代,干净代码不仅仅是好的实践 — 它是能够扩展的系统与在自己的重量下崩溃的代码库之间的区别。

模型-视图-控制器 图解实用指南 | Clean Code Guy