前端架构模式哪家强?MVC vs MVVM 深度剖析,附三大框架 Vue、React、Angular 实战

338 阅读9分钟

前端架构模式哪家强?MVC vs MVVM 深度剖析,附三大框架 Vue、React、Angular 实战

在前端开发的江湖中,架构模式犹如大侠们的绝世武功秘籍,选对了便能在代码的江湖中披荆斩棘,MVC 与 MVVM 便是其中备受瞩目的两大 “神功”。今天,咱们就来深入剖析这两种架构模式,再结合 Vue、React、Angular 三大框架的实战案例,看看谁才是最适合你的 “武功秘籍”。

MVC:经典的 “三板斧”

MVC 即 Model - View - Controller,是一种历史悠久且广泛应用的架构模式,就像江湖中流传已久的经典武功,有着清晰的招式套路。

Model:数据的 “藏经阁”

Model 层负责管理应用程序的数据和业务逻辑,它就像是一个庞大的藏经阁,存储着各种珍贵的 “数据秘籍”。在一个电商应用中,商品信息、用户订单数据等都归 Model 管。它不仅存储数据,还负责处理数据的增删改查等操作,保障数据的一致性和完整性。以下是一个简单的 JavaScript 示例,模拟一个管理用户数据的 Model:

// 用户数据Model
const userModel = {
    users: [],
    addUser: function (user) {
        this.users.push(user);
    },
    getUserById: function (id) {
        return this.users.find(user => user.id === id);
    }
};

View:用户的 “视觉盛宴”

View 层专注于将 Model 中的数据呈现给用户,是用户与应用交互的可视化界面。它就像是一场精心编排的视觉盛宴,通过 HTML、CSS 和 JavaScript(用于动态交互效果),把数据以美观、易用的方式展示出来。比如电商应用的商品列表页面、购物车页面等,用户看到的各种界面元素都是 View 层的杰作。以下是一个简单的 HTML 和 JavaScript 结合的 View 示例,用于展示用户列表:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>User View</title>
</head>
<body>
    <ul id="userList"></ul>
    <script>
        const userList = document.getElementById('userList');
        const renderUsers = function (users) {
            userList.innerHTML = '';
            users.forEach(user => {
                const li = document.createElement('li');
                li.textContent = `ID: ${user.id}, Name: ${user.name}`;
                userList.appendChild(li);
            });
        };
    </script>
</body>
</html>

Controller:协调的 “武林盟主”

Controller 层起着桥梁的作用,连接着 View 和 Model。它接收用户在 View 层的操作,比如点击按钮、提交表单等,然后根据这些操作决定调用 Model 层的哪些方法来处理数据,最后再根据 Model 层返回的结果,决定如何更新 View 层。它如同武林盟主,协调各方,确保整个应用的流畅运行。在电商应用里,当用户点击 “加入购物车” 按钮时,Controller 会捕获这个事件,调用 Model 层添加商品到购物车的方法,然后通知 View 层更新购物车的显示。以下是结合前面 Model 和 View 示例的 Controller 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>User MVC Example</title>
</head>
<body>
    <ul id="userList"></ul>
    <button id="addUserButton">Add User</button>
    <script>
        // 用户数据Model
        const userModel = {
            users: [],
            addUser: function (user) {
                this.users.push(user);
            },
            getUserById: function (id) {
                return this.users.find(user => user.id === id);
            }
        };
        const userList = document.getElementById('userList');
        const renderUsers = function (users) {
            userList.innerHTML = '';
            users.forEach(user => {
                const li = document.createElement('li');
                li.textContent = `ID: ${user.id}, Name: ${user.name}`;
                userList.appendChild(li);
            });
        };
        const userController = {
            init: function () {
                const addUserButton = document.getElementById('addUserButton');
                addUserButton.addEventListener('click', () => {
                    const newUser = { id: Date.now(), name: 'New User' };
                    userModel.addUser(newUser);
                    renderUsers(userModel.users);
                });
                renderUsers(userModel.users);
            }
        };
        userController.init();
    </script>
</body>
</html>

MVC 的优缺点

MVC 的优点十分显著,它的职责划分清晰,使得团队开发时,不同成员可以专注于自己负责的层,提高开发效率。而且代码的可维护性和可扩展性也较好,就像一座结构稳固的大厦,后续修改和添加功能都相对容易。不过,它也并非完美无缺。随着应用变得复杂,Controller 可能会变得臃肿不堪,就像一个承担过多任务的武林盟主,力不从心。而且,Model 和 View 之间的同步需要手动处理,这无疑增加了开发的工作量和出错的概率。

MVC 在框架中的体现:以 Angular 为例

在 Angular 框架中,MVC 模式有着典型的应用。在 Angular 应用里,服务(Service)常常扮演着 Model 的角色,负责数据的获取和处理。例如,创建一个获取用户信息的服务:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
    providedIn: 'root'
})
export class UserService {
    private apiUrl = 'https://example.com/api/users';
    constructor(private http: HttpClient) {}
    getUsers(): Observable<any[]> {
        return this.http.get<any[]>(this.apiUrl);
    }
}

视图模板(Template)就是 View 层,通过 HTML 结合 Angular 的指令(Directive),将数据展示给用户。比如,使用*ngFor指令可以方便地遍历数据列表并展示在页面上:

<ul>
    <li *ngFor="let user of users">{{ user.name }}</li>
</ul>

控制器(Controller)则是连接两者的纽带,在 Angular 中,组件(Component)承担了部分 Controller 的职责。组件接收用户在视图上的操作,调用服务中的方法来处理数据,然后更新视图。例如,在一个用户登录组件中:

import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';
@Component({
    selector: 'app - user - login',
    templateUrl: './user - login.component.html',
    styleUrls: ['./user - login.component.css']
})
export class UserLoginComponent implements OnInit {
    users: any[] = [];
    constructor(private userService: UserService) {}
    ngOnInit(): void {
        this.userService.getUsers().subscribe(users => {
            this.users = users;
        });
    }
}

MVVM:进化的 “新派武功”

MVVM 即 Model - View - ViewModel,是在 MVC 基础上发展而来的一种新架构模式,如同新派武功,融合了前辈的精华并有所创新。

Model:初心未改的数据担当

在 MVVM 中,Model 层的职责与 MVC 中的 Model 类似,依然负责管理数据和业务逻辑。它就像一位坚守岗位的老侠客,不管江湖格局如何变化,始终守护着数据的 “江湖”。同样以用户数据为例,Model 的代码可以如下:

const userModel = {
    users: [],
    addUser: function (user) {
        this.users.push(user);
    },
    getUserById: function (id) {
        return this.users.find(user => user.id === id);
    }
};

View:专注展示的 “门面担当”

View 层同样负责呈现数据给用户,不过在 MVVM 中,它与 Model 层的耦合度更低,更加专注于展示功能。它就像一家店铺的精美橱窗,只负责将商品(数据)以吸引人的方式展示出来,而不关心商品是如何进货(数据如何获取和处理)的。一个简单的 HTML 视图示例如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>User View</title>
</head>
<body>
    <ul id="userList"></ul>
</body>
</html>

ViewModel:神奇的 “数据粘合剂”

ViewModel 是 MVVM 的核心创新之处,它就像一位神奇的粘合剂大师,将 View 和 Model 巧妙地连接在一起。ViewModel 负责暴露 Model 中的数据,使其能方便地被 View 使用,同时处理 View 的交互逻辑。它还通过数据绑定机制,实现了 View 和 Model 之间的自动同步。也就是说,当 Model 中的数据发生变化时,ViewModel 会自动通知 View 更新显示;反之,当用户在 View 上进行操作导致数据变化时,ViewModel 也会自动更新 Model。比如在一个实时聊天应用中,当收到新消息时(Model 数据变化),ViewModel 会自动让 View 更新聊天记录的显示;用户发送新消息(View 操作),ViewModel 会将新消息数据更新到 Model 中。以下是一个简单的 MVVM 示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>MVVM Example</title>
</head>
<body>
    <ul id="userList"></ul>
    <button id="addUserButton">Add User</button>
    <script>
        const userModel = {
            users: [],
            addUser: function (user) {
                this.users.push(user);
            },
            getUserById: function (id) {
                return this.users.find(user => user.id === id);
            }
        };
        const userViewModel = {
            users: userModel.users,
            addUser: function () {
                const newUser = { id: Date.now(), name: 'New User' };
                userModel.addUser(newUser);
            }
        };
        const userList = document.getElementById('userList');
        const renderUsers = function () {
            userList.innerHTML = '';
            userViewModel.users.forEach(user => {
                const li = document.createElement('li');
                li.textContent = `ID: ${user.id}, Name: ${user.name}`;
                userList.appendChild(li);
            });
        };
        const addUserButton = document.getElementById('addUserButton');
        addUserButton.addEventListener('click', userViewModel.addUser);
        const observer = new MutationObserver(() => {
            renderUsers();
        });
        const targetNode = userViewModel;
        const config = { attributes: true, childList: true, subtree: true };
        observer.observe(targetNode, config);
        renderUsers();
    </script>
</body>
</html>

MVVM 的优缺点

MVVM 最大的优势在于数据绑定带来的高效开发体验。开发人员无需手动频繁地更新 View 以同步 Model 的数据变化,大大减少了代码量和出错的可能性,开发效率大幅提升。而且,由于 View 和 Model 通过 ViewModel 解耦,使得代码的可测试性和可维护性都得到了增强。当然,它也有一些小麻烦。对于初学者来说,理解 ViewModel 和数据绑定机制可能需要花费一些时间和精力,就像学习新派武功需要先领悟其独特的内功心法。另外,如果在应用中过度使用数据绑定,可能会对性能产生一定影响。

MVVM 在框架中的体现:以 Vue 和 React 为例

Vue 中的 MVVM 实现

Vue 是 MVVM 模式的典型代表,数据绑定是其核心特性之一。在 Vue 中,通过data选项定义的数据就是 Model 层的数据。例如:

new Vue({
    el: '#app',
    data: {
        message: 'Hello, Vue!'
    }
});
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>Vue MVVM Example</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <p>{{ message }}</p>
    </div>
</body>
</html>

当message数据发生变化时,视图会自动更新。Vue 还通过v - model指令实现了双向数据绑定,特别适用于表单元素。例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>Vue v - model Example</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <input v - model="message">
        <p>{{ message }}</p>
    </div>
    <script>
        new Vue({
            el: '#app',
            data: {
                message: ''
            }
        });
    </script>
</body>
</html>

这样,输入框的值会与message数据实时同步,用户输入会更新message,message的变化也会实时显示在输入框中。

React 中的 MVVM 体现

React 虽然没有像 Vue 那样直接实现双向数据绑定,但通过单向数据流和状态管理机制,也体现了 MVVM 的思想。在 React 中,组件的状态(state)可以看作是 Model 层的数据。例如:

import React, { useState } from'react';
import ReactDOM from'react - dom';
function MyComponent() {
    const [count, setCount] = useState(0);
    return (
        <div>
            <p>{count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}
ReactDOM.render(<MyComponent />, document.getElementById('root'));
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF - 8">
    <title>React MVVM Example</title>
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react - dom@17/umd/react - dom.development.js"></script>
</head>
<body>
    <div id="root"></div>
</body>
</html>

这里的count就是数据,setCount函数用于更新数据。当count变化时,组件会重新渲染,视图也随之更新,这类似于 MVVM 中 Model 变化自动更新 View 的机制。虽然 React 本身没有内置双向数据绑定,但通过一些库(如 Formik 等)可以实现类似的双向绑定效果,用于处理表单等场景。

MVC 与 MVVM 对比总结

关注点分离

MVC 中,Controller 承担了较多的职责,包括协调 Model 和 View 的交互以及处理用户输入等,View 与 Controller 和 Model 的联系较为紧密。而 MVVM 更加明确地将视图和模型的逻辑分离,ViewModel 专注于处理视图的展示逻辑和与模型的交互,View 相对更加独立,对 Model 的依赖较少。

数据绑定机制

MVC 中通常需要手动在 Controller 中更新 View,而 MVVM 强调数据绑定,模型的变化可以自动反映在视图上,减少了大量手动更新视图的代码,开发效率更高。

代码结构与维护

MVC 的代码结构在大型项目中可能会显得较为复杂,Controller 容易变得臃肿,导致维护难度增加。MVVM 的代码结构相对更加清晰,逻辑层次分明,使得代码的维护和扩展更加容易。

测试难度

MVC 中 Controller 和 View 的耦合度较高,可能会增加测试的难度,需要更多地考虑两者之间的交互。MVVM 由于 ViewModel 的存在,使得测试更加容易聚焦和隔离,可以方便地对 Model、ViewModel 和 View 进行单独测试。

结语

MVC 和 MVVM 各有千秋,MVC 作为经典架构模式,在传统 Web 应用开发等领域依然有着广泛的应用,其清晰的职责划分对于理解和构建应用有很大帮助。而 MVVM 作为后起之秀,凭借数据绑定等特性,在现代前端开发,尤其是单页应用(SPA)和移动应用开发中大放异彩,大大提升了开发效率和用户体验。

在实际项目中,选择 MVC 还是 MVVM,需要根据项目的具体需求、团队的技术栈以及开发者对不同模式的熟悉程度来决定。就像大侠们选择武功秘籍,适合自己的才是最好的。希望通过本文的介绍,你能对 MVC 和 MVVM 有更深入的理解。