MVC 是一种按职责组织代码和服务的架构思想。三个字母分别代表 Model、View 和 Controller。它不是某个框架,也不要求项目中必须存在三个同名文件夹;关键是让展示、流程控制和数据状态各有明确归属。

三层分别做什么

可以把它理解为负责不负责
View(视图)用户看见和操作的界面渲染内容、收集点击和输入、展示加载或错误状态决定权限、直接操作数据库
Controller(控制器)请求的指挥者接收请求、校验权限、安排调用顺序、组合结果长期保存业务数据
Model(模型)数据和业务状态的所有者定义实体、查询和修改数据、通过仓储接口持久化渲染界面、编排整个用户流程
最简短的记忆方式是:View 负责显示,Controller 负责协调,Model 负责数据。

一个具体例子

假设用户点击“收藏句子”:
  1. Flutter 页面接收点击并发送收藏请求,这是 View 的工作。
  2. 服务端识别当前用户、检查请求是否合法,并决定调用哪个数据服务,这是 Controller 的工作。
  3. 收藏服务创建收藏记录并写入数据库,这是 Model 的工作。
  4. 结果沿原路返回,View 再更新按钮状态。
如果应用重启后收藏仍然存在,是因为状态由 Model 持久化了,而不是由页面或 Controller 暂存。

在 RakuLLApp 中如何对应

MVC 角色RakuLLApp 组件
Viewrakullapp_corerakull_manager
Controllerimmersive_study_servermanager_server
Modeldata_serveruser_managercollection_server
MVC 之外的计算黑盒agent_server
agent_server 负责 AI 计算,但不拥有计算结果。Controller 调用它取得结果后,再交给相应的 Model 保存。因此即使替换 Agent,已经保存的文章、句子和讲解仍属于 Model。
RakuLLApp 的 MVC 是服务级职责划分,不是传统单体 Web 框架中一个请求严格经过三个类的写法。

为什么要这样分层

  • 容易定位修改位置:界面问题看 View,流程和权限看 Controller,数据问题看 Model。
  • 降低耦合:更换 Flutter 页面或 AI 实现时,不必迁移业务数据。
  • 更容易测试:Controller 可以用假的下游服务测试编排;Model 可以独立测试读写。
  • 避免状态混乱:同一种实体只有一个明确的所有者,不会在多个服务中各存一份真相。

常见误解

Model 不只是数据库表

Model 还包括实体约束、仓储接口和数据读写规则。数据库只是它实现持久化的一种方式。

Controller 不是“所有业务代码”

Controller 负责一次请求的流程和权限,但实体自身的数据规则应留在拥有该实体的 Model 中。

View 可以有界面状态

输入框内容、当前选中的标签页、加载动画等短期 UI 状态可以留在 View。不能放在 View 的是文章、收藏、用户权限等需要长期保存或跨客户端一致的业务状态。 接下来可阅读 架构总览,了解这些职责在实际服务中的完整分布。