Skip to content

MVC

MVC(Model-View-Controller) 是一种软件设计模式,用于将应用程序分为三个主要组件:模型(Model)视图(View)控制器(Controller)。它通过分离关注点(Separation of Concerns)提高代码的可维护性、可扩展性和可测试性,广泛应用于 Web 应用、桌面应用和移动应用开发。

核心组件

  1. 模型(Model)

    • 负责管理应用的数据和业务逻辑。
    • 直接与数据库、API 等数据源交互。
    • 当数据变化时,通知视图更新。
  2. 视图(View)

    • 负责呈现数据(UI)给用户。
    • 监听模型变化并更新界面。
    • 不处理业务逻辑,仅展示数据。
  3. 控制器(Controller)

    • 接收用户输入(如点击、表单提交)。
    • 调用模型处理数据。
    • 根据模型状态选择合适的视图展示结果。

工作流程

MVC 的数据流通常遵循以下步骤:

  1. 用户交互:用户通过视图触发操作(如点击按钮)。
  2. 控制器接收请求:视图将用户输入传递给控制器。
  3. 控制器处理请求:控制器调用模型的方法处理业务逻辑。
  4. 模型更新数据:模型执行操作(如查询数据库、计算结果)。
  5. 模型通知视图:数据变化后,模型通知视图更新。
  6. 视图刷新界面:视图获取最新数据并重新渲染。
用户 → 视图 → 控制器 → 模型 → 视图(更新)

示例:简单的待办事项应用

以下是一个简化的 MVC 实现示例(使用 JavaScript):

1. 模型(Model)

javascript
class TodoModel {
  constructor() {
    this.todos = [];
    this.observers = [];
  }

  // 添加观察者(视图)
  addObserver(observer) {
    this.observers.push(observer);
  }

  // 通知所有观察者数据已更新
  notifyObservers() {
    this.observers.forEach((observer) => observer.update());
  }

  // 添加待办事项
  addTodo(text) {
    this.todos.push({ id: Date.now(), text, completed: false });
    this.notifyObservers();
  }

  // 删除待办事项
  removeTodo(id) {
    this.todos = this.todos.filter((todo) => todo.id !== id);
    this.notifyObservers();
  }

  // 获取所有待办事项
  getAll() {
    return this.todos;
  }
}

2. 视图(View)

javascript
class TodoView {
  constructor(controller) {
    this.controller = controller;
    this.container = document.createElement("div");
    this.render();
  }

  // 渲染视图
  render() {
    this.container.innerHTML = `
      <input type="text" id="todo-input" placeholder="添加待办事项">
      <button id="add-button">添加</button>
      <ul id="todo-list"></ul>
    `;

    // 绑定事件到控制器
    document.getElementById("add-button").addEventListener("click", () => {
      const input = document.getElementById("todo-input");
      this.controller.addTodo(input.value);
      input.value = "";
    });
  }

  // 更新视图(由模型通知)
  update() {
    const todoList = document.getElementById("todo-list");
    todoList.innerHTML = "";

    const todos = this.controller.getTodos();
    todos.forEach((todo) => {
      const li = document.createElement("li");
      li.textContent = todo.text;
      li.innerHTML += ` <button data-id="${todo.id}">删除</button>`;
      li.querySelector("button").addEventListener("click", () => {
        this.controller.removeTodo(todo.id);
      });
      todoList.appendChild(li);
    });
  }
}

3. 控制器(Controller)

javascript
class TodoController {
  constructor(model) {
    this.model = model;
  }

  // 添加待办事项
  addTodo(text) {
    if (text.trim()) {
      this.model.addTodo(text);
    }
  }

  // 删除待办事项
  removeTodo(id) {
    this.model.removeTodo(id);
  }

  // 获取所有待办事项
  getTodos() {
    return this.model.getAll();
  }
}

4. 初始化应用

javascript
// 创建 MVC 实例并关联
const model = new TodoModel();
const controller = new TodoController(model);
const view = new TodoView(controller);

// 将视图添加到 DOM
document.body.appendChild(view.container);

// 注册视图为模型的观察者
model.addObserver(view);

MVC 的变体

  1. MVVM(Model-View-ViewModel)

    • 使用 ViewModel 替代 Controller,通过数据绑定自动同步视图和模型。
    • 典型框架:Vue.js、Angular。
  2. MVP(Model-View-Presenter)

    • Presenter 与 View 强耦合,负责处理视图逻辑。
    • 常用于测试驱动开发(TDD)。
  3. Flux/Redux

    • 单向数据流架构,更适合复杂应用状态管理。

优缺点

优点缺点
分离关注点,提高代码可维护性架构复杂度较高,小型应用可能冗余
支持并行开发(视图和逻辑分离)控制器可能变得庞大(Massive Controller)
便于单元测试(模型和控制器可独立测试)视图与模型的双向依赖可能导致紧耦合

适用场景

  • 中大型应用,尤其是需要多人协作开发的项目。
  • 需要频繁修改视图或业务逻辑的场景。
  • 需要支持多种视图展示同一数据的应用(如 Web 端和移动端)。

总结

MVC 是一种经典的软件架构模式,通过分离数据、视图和控制逻辑,使代码更易于维护和扩展。虽然现代前端框架(如 React、Vue)可能采用不同的架构模式(如单向数据流),但 MVC 的核心思想(关注点分离)仍然是软件设计的重要原则。

Released under the MIT License.