模块化与工程化
约 1568 字大约 5 分钟
2025-11-24
MVC、MVVM、MVP
问题
什么是MVC模式?
什么是MVVM模式?
什么是MVP模式?
在前端开发中,MVC、MVVM 和 MVP 是三种常见的软件设计模式,它们帮助开发者更高效地组织代码,提升代码的可维护性、可扩展性和可测试性。
MVC
概念
MVC 模式将应用程序分为三个主要部分:模型(Model)、视图(View)和控制器(Controller),各部分之间的职责明确且相互协作。
- 模型(
Model):负责处理应用程序的数据逻辑和业务规则,例如数据的存储、获取、更新和验证等操作。模型是独立于用户界面的,它可以被多个视图复用。 - 视图(
View):负责将模型中的数据以可视化的方式呈现给用户,通常是 HTML、CSS 和 JavaScript 构建的用户界面。视图只负责展示数据,不处理业务逻辑。 - 控制器(
Controller):作为模型和视图之间的桥梁,接收用户的输入(如点击事件、表单提交等),根据用户输入调用模型的相应方法进行数据处理,然后根据处理结果更新视图。
工作流程
- 用户与视图进行交互,触发相应的事件。
- 视图将事件传递给控制器。
- 控制器根据事件调用模型的方法进行数据处理。
- 模型处理完数据后,将结果返回给控制器。
- 控制器根据模型的结果更新视图。
优缺点
- 优点:职责分离,便于代码的维护和扩展;模型和视图可以独立开发和测试。
- 缺点:控制器可能会变得过于庞大,包含过多的业务逻辑;视图和模型之间的耦合度较高,修改视图可能会影响到模型,反之亦然。
- 应用:传统后端框架(如 Spring MVC)。
MVVM
概念
MVVM 模式是在 MVC 模式的基础上发展而来的,它引入了视图模型(ViewModel)的概念,通过数据绑定和视图模型来实现视图和模型的分离。
- 模型(
Model):与 MVC 中的模型类似,负责处理数据和业务逻辑。 - 视图(
View):负责用户界面的展示,通常由 HTML 和 CSS 构建。 - 视图模型(
ViewModel):是视图和模型之间的桥梁,它包含了视图的状态和行为,并通过数据绑定机制将视图和模型连接起来。视图模型负责处理视图的交互逻辑,同时将视图的变化反映到模型中,反之亦然。
工作流程
- 视图模型通过数据绑定机制将模型的数据绑定到视图上,实现数据的自动更新。
- 用户与视图进行交互,触发视图的事件。
- 视图模型监听视图的事件,并根据事件更新模型的数据。
- 模型的数据更新后,通过数据绑定机制自动更新视图。
优缺点
- 优点:通过数据绑定和视图模型实现了视图和模型的解耦,降低了代码的耦合度,提高了代码的可维护性和可测试性;开发人员可以专注于业务逻辑的实现,而不需要手动操作
DOM。 - 缺点:数据绑定的实现可能会增加一定的性能开销;对于简单的应用程序,使用 MVVM 模式可能会显得过于复杂。
- 应用:现代前端框架(如 Vue、Angular、React + 状态管理)。
MVP
概念
MVP 模式也是从 MVC 模式演变而来的,它将控制器替换为了 Presenter,进一步强调了视图和模型的分离。
- 模型(
Model):同样负责数据和业务逻辑的处理。 - 视图(
View):负责用户界面的展示,只负责显示数据和接收用户的输入,不包含任何业务逻辑。 - Presenter:作为视图和模型之间的中介,负责处理视图的交互逻辑和业务逻辑。Presenter 接收视图的事件,调用模型的方法进行数据处理,然后根据处理结果更新视图。
工作流程
- 用户与视图进行交互,触发视图的事件。
- 视图将事件传递给
Presenter。 Presenter根据事件调用模型的方法进行数据处理。- 模型处理完数据后,将结果返回给Presenter。
Presenter根据模型的结果更新视图。
优缺点
- 优点:视图和模型之间的耦合度较低,便于代码的维护和测试;
Presenter可以独立于视图和模型进行开发和测试。
CommonJS 与 ES6 导入模块的区别?
CommonJS 导入导出
CommonJS 的导入导出是 Nodejs 早期原生支持的方式,ES6 的导入导出可以通过工具如 Babel 转换为 CommonJS 的方式。
- 导入导出语法
// 导出
const name = 'moduleA'
module.exports = {
name
}
// 引入
const moduleA = require('./moduleA')- 特点
CommonJS 还可以动态导入导出,通过条件判断甚至在函数体内导出模块。
if (condition) { exports.name = 'moduleA' } else { exports.name = 'moduleB' } function exportModule() { exports.name = 'moduleA' }require 是运行时加载(同步加载),且在 require 时会加载和立即执行。
导出的是值的拷贝,但是导入的引用类型共享同一引用。
ES6 导入导出
- 导入导出语法
// 导出
export const name = 'moduleA'
// 默认导出
export default 'moduleA'
// 引入
import { name } from './moduleA'- 特点
ES6 导入导出是静态的,即在编译时确定要导入的模块,而不是在运行时,这使得它可以在编译时确定依赖关系。所以它不允许像 CommonJS 那样动态导入导出模块。
ES6 导入是异步加载,不会阻塞其他加载过程。
ES6 导出的是值的引用,修改会影响所有导入该值的地方。
ESM 的设计更利于现代工具链优化和浏览器原生支持,是如今项目首推的导入导出方式。除非你有动态导入模块的场景,否则更推荐使用 ES6 导入导出的方式。