MVC 架构模式解析

MVC 架构模式

核心定义

MVC 是一种将应用拆分为三部分的架构模式:

  • Model(模型):管理数据和业务逻辑
  • View(视图):负责界面展示
  • Controller(控制器):接收用户输入,协调 Model 和 View

通信规则

用户操作 → View → Controller → Model → View

三条铁律:

  1. View 不能直接调用 Model(必须通过 Controller)
  2. Model 不能直接操作 DOM(只能通知 View 去 render)
  3. 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 来保持清晰的职责分离。

← 返回列表