当前位置: 首页 > news >正文

Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析

Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析

一、框架演变:从Vue2到Vue3的跨越

1.1 革命性升级

Vue3的发布标志着前端框架进入新纪元,其核心改进体现在三个方面:

  • 性能飞跃:包体积减少41%,初始渲染提速55%,更新性能提升133%
  • 开发体验:Composition API带来更好的逻辑复用能力
  • 未来兼容:完善的TypeScript支持与渐进式升级策略

1.2 兼容性设计

通过@vue/compat适配层实现平滑升级:

// vue.config.js
module.exports = {chainWebpack: config => {config.resolve.alias.set('vue', '@vue/compat')}
}

保留Options API的同时支持Composition API,新旧范式共存的设计保障了项目渐进式迁移。


二、架构革新:Monorepo与原子化设计

2.1 模块化重构

采用Monorepo架构拆分为独立子包:

packages/
├── compiler-core     // 核心编译逻辑
├── reactivity        // 响应式系统
├── runtime-core      // 运行时核心
└── shared            // 公共工具库

每个模块可独立构建、测试和发布,通过pnpm进行依赖管理。

2.2 TypeScript转型

源码TS覆盖率从Vue2的0%提升到Vue3的98%,类型系统带来的优势:

interface ComponentInternalInstance {uid: numbertype: ConcreteComponentparent: ComponentInternalInstance | nullappContext: AppContext
}

强类型约束使代码更健壮,配合Volar插件提供精准的类型提示。


三、性能优化四大支柱

3.1 API精简策略

移除filter$on/$off等低频API,通过插件机制实现按需引入。

3.2 Tree-shaking优化

基于ESM的模块设计:

// 按需导入
import { ref, reactive } from '@vue/reactivity'

配合Rollup实现Dead Code Elimination,基础运行时仅12.5KB。

3.3 响应式系统重构

特性Vue2(Object.defineProperty)Vue3(Proxy)
检测范围对象属性完整对象
数组检测需要hack处理原生支持
新增属性需要$set直接响应
性能影响递归初始化按需代理

3.4 底层优化

  • 事件缓存:将事件处理函数缓存到_cache数组
  • 静态提升:将静态节点提升到渲染函数外部
  • 补丁标记:动态绑定采用二进制位标记优化diff算法

四、编译时优化:智能的模板编译

4.1 静态分析

编译阶段生成带有PatchFlag的虚拟DOM:

// 编译前
<div>{{ msg }}</div>// 编译后
_createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)

64种PatchFlag类型标识动态节点类型,优化diff过程。

4.2 Block Tree机制

通过动态节点收集器建立更新区块:

const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "Static Content", -1 /* HOISTED */)function render() {return (_openBlock(), _createBlock("div", null, [_hoisted_1,_createVNode("span", null, _toDisplayString(_ctx.dynamic), 1 /* TEXT */)]))
}

静态内容被提升到渲染函数外部,避免重复创建。


五、核心源码解析

5.1 响应式系统实现

Vue3的响应式核心(@vue/reactivity):

// 响应式入口
function reactive(target) {return createReactiveObject(target, mutableHandlers)
}// Proxy处理器
const mutableHandlers = {get(target, key, receiver) {track(target, 'get', key)return Reflect.get(target, key, receiver)},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver)trigger(target, 'set', key)return result}
}

5.2 虚拟DOM优化

function patch(n1, n2, container) {if (n1 == null) {mountElement(n2, container)} else {updateElement(n1, n2, container)}
}function updateElement(n1, n2, container) {const el = (n2.el = n1.el)if (n2.patchFlag & PatchFlags.CLASS) {if (n1.class !== n2.class) {el.className = n2.class}} else {// 全量diff}
}

六、框架对比总结

维度Vue2Vue3
响应式系统Object.definePropertyProxy
源码组织单体仓库Monorepo
类型支持FlowTypeScript
包体积完整打包按需引入
性能优化手动优化编译时自动优化
API设计Options APIComposition API

七、手写响应式系统实现

const targetMap = new WeakMap()
let activeEffect = nullfunction track(target, key) {if (!activeEffect) returnlet depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = new Set()))}dep.add(activeEffect)
}function trigger(target, key) {const depsMap = targetMap.get(target)if (!depsMap) returnconst effects = depsMap.get(key)effects && effects.forEach(effect => effect())
}function reactive(obj) {return new Proxy(obj, {get(target, key, receiver) {track(target, key)return Reflect.get(target, key, receiver)},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver)trigger(target, key)return result}})
}function effect(fn) {activeEffect = fnfn()activeEffect = null
}// 使用示例
const state = reactive({ count: 0 })
effect(() => {console.log('Count:', state.count)
}) // 输出 Count: 0state.count++ // 输出 Count: 1

结语

Vue3的架构演进体现了现代前端框架的发展方向:更精细的模块化、更智能的编译优化、更强大的类型支持。通过深入源码理解其设计哲学,不仅能提升开发技能,更能帮助我们做出合理的架构决策。建议结合官方源码导读,从packages/reactivity模块开始逐步深入探索。

相关文章:

Vue源码深度解析:从2.x到3.x的架构演进与核心原理剖析

Vue源码深度解析&#xff1a;从2.x到3.x的架构演进与核心原理剖析 一、框架演变&#xff1a;从Vue2到Vue3的跨越 1.1 革命性升级 Vue3的发布标志着前端框架进入新纪元&#xff0c;其核心改进体现在三个方面&#xff1a; 性能飞跃&#xff1a;包体积减少41%&#xff0c;初始…...

评委打分5个评委 去掉一个最高分和一个最低分 取平均分

一键替换max用min 按shiftF6 public static int getMin(int[]scores){int min scores[0];for (int i 0; i < scores.length; i) {if(scores[i]> min){min scores[i];}}return min;} 这里有和c/c不一样的知识点 c/c调用函数类似于java的方法,但是c/c的函数调用需要声明…...

javabean类(测试类之外的类)

altinsert快捷键生成构造方法和get、set方法 或者插件ptg&#xff08;连接外网搜索插件并且下载&#xff09;...

C++ 邻接矩阵(代码)

C邻接矩阵代码&#xff0c;见下&#xff1a; #include<iostream>using namespace std;#define inf -1 class Graph{ private:int vertices;int **edges;public:Graph(int vertices);~Graph();void addEdge(int u, int v, int w);void printGraph(); };Graph::Graph(int …...

Cookie与Session详解

Cookie简介 Cookie 是浏览器提供的持久化存储数据的一种机制。是指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地终端上的数据&#xff08;通常经过加密&#xff09;。以下是关于 Cookie 的详细介绍&#xff1a; Cookie工作原理 当你访问一个网站时&#xff0c;该网…...

OpenBMC:BmcWeb 处理http请求

OpenBMC:BmcWeb 读取http请求头-CSDN博客 介绍了,在读取完http头后,将调用Connection::handle处理http请求 1.Connection::handle void handle() {...req = std::make_shared<crow::Request>(parser->release(), reqEc);...req->session = userSession;accept …...

【算法题解答·六】栈队列堆

【算法题解答六】栈队列堆 接上文【算法方法总结六】栈队列堆的一些技巧和注意事项 栈队列堆相关题目如下&#xff1a; 232.用栈实现队列 简单 准备两个栈&#xff0c;一个负责入队的栈A&#xff0c;一个负责出队的栈B出队和返回队列开头元素&#xff0c;都要先进行以下操作…...

计算机视觉算法实战——手势识别(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 领域简介&#xff1a;手势识别的价值与挑战 手势识别是连接人类自然行为与数字世界的核心交互技术&#xff0c;在智能设备控制、…...

JobScheduler省电机制

1.前言 JobScheduler&#xff08;任务调度器&#xff09;是 Android 提供的一种任务调度机制&#xff0c;可以替代传统的 WakeLock 和 Alarm 来执行后台任务。那么&#xff0c;它们之间的区别是什么&#xff1f;JobScheduler 又有哪些特别之处呢&#xff1f; 1.1 WakeLock 和 …...

设计模式学习笔记——命令模式

2025年3月13日&#xff0c;周四下午 相同的保存逻辑在各个组件中重复出现。 且需要修改保存逻辑时&#xff0c;各个组件的保存逻辑都需要进行相应修改。 使用了命令模式把保存逻辑从三个组件中独立出来后&#xff0c;减少了代码冗余。 可以通过“保存命令”来使用保存逻辑&am…...

[TPCTF 2025] crypto 复现两题

周末很忙。比赛都没怎么看。晚上把密码复现两个。 randomized random 这题在小鸡块博客里见过&#xff0c;稍有区别。 # FROM python:3 import random with open("flag.txt","rb") as f:flagf.read() for i in range(2**64):print(random.getrandbits(3…...

电子元器件选型与实战应用—16 怎么选一个合适的MCU芯片?

文章目录 1. 选型要素1.1 价格1.2 技术支持1.3 厂家优势1.4 功耗1.5 特殊功能1.6 统计外设1.7 确定外设占用的内存和flash大小1.8 确定外设通信接口1.9 确定外设通信接口的电平1.10 确定外设的GPIO数量1.11 确定外设的供电和功耗1.12 确定外设GPIO的种类1.13 确定ADC的数量1.14…...

第6关:牛牛鱼缸-附加题

任务描述 本关任务&#xff1a;问题描述&#xff1a;牛牛有一个鱼缸&#xff0c;鱼缸里面已经有n条鱼&#xff0c;每条鱼的大小为fishSizei&#xff0c;牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸里存在着大鱼吃小鱼的定律。经过观察&#xff0c;牛牛发现一条鱼A的大小为另外一条鱼…...

go中间件学习

本博文源于笔者正在学习go中间件&#xff0c;罗列了较为常用的中间件&#xff0c;例如日志记录、认证授权、跨域资源共享、请求体解析、静态文件处理、错误处理、性能分析、速率限制、session 1、日志记录中间件 可以追加打印用&#xff0c;例如&#xff0c;将请求进行打印 …...

若依RuoYi-Cloud-Plus微服务版(完整版)前后端部署

一.目标 在浏览器上成功登录进入 二.源码下载 后端源码&#xff1a;前往Gitee下载页面(https://gitee.com/dromara/RuoYi-Cloud-Plus)下载解压到工作目录。 前端源码&#xff1a; 前往Gitee下载页面(https://gitee.com/JavaLionLi/plus-ui)下载解压到工作目录。 文档地址&a…...

航空电动力系统适航标准要点手册

航空电动力系统适航标准要点手册 1.标准制定背景与必要性1.1 为什么需要制定和遵循标准&#xff1f;1.2 标准制定依据与发布机构 2.关键核心标准概述2.1 电动航空与电推进系统2.2 混合动力系统2.3 硬件与通用要求 3.标准详细解读与应用场景3.1 DO-160G&#xff1a;环境适应性测…...

深入理解JavaScript构造函数与原型链:从原理到最佳实践

一、开篇&#xff1a;为什么需要理解原型链&#xff1f; 在JavaScript开发中&#xff0c;90%以上的"诡异"bug都与原型链机制相关。理解构造函数与原型链的运行原理&#xff0c;不仅能帮助我们写出更优雅的代码&#xff0c;还能在框架源码阅读、性能优化等场景中游刃…...

java每日精进 3.12 【WebSocket进阶】

基于 SpringWebSocket 进行二次封装&#xff0c;实现了更加简单的使用方式。例如说&#xff0c;WebSocket 的认证、Session 的管理、WebSocket 集群的消息广播等等。 1. 用户认证与登录用户信息传递 1.1 Token 过滤器 (TokenAuthenticationFilter) ① 在 WebSocket 连接建立…...

国家网络安全事件应急预案

目 录 1 总则 1.1 编制目的 1.2 编制依据 1.3 适用范围 1.4 事件分级 1.5 工作原则 2 组织机构与职责 2.1 领导机构与职责 2.2 办事机构与职责 2.3 各部门职责 2.4 各省&#xff08;区、市&#xff09;职责 3 监测与预警 3.1 预警分级 3.2 预警监测 3.3 预警研判…...

Markdown:Mermaid 画图

目录 安装基本语法流程图时序图甘特图总结 Mermaid 是一款用于生成流程图、时序图、甘特图等图表的 JavaScript 库。它可以将简单的文本描述转化为美观的图表&#xff0c;方便开发者进行可视化展示。 安装 Mermaid 可以直接在浏览器中使用&#xff0c;也可以在 Node.js 环境中…...

【视频】ffmpeg、Nginx搭建RTMP、HLS服务器

1、源码安装Nginx 1)源码下载 因为要使用Nginx的模块nginx-rtmp-module,所以要下载 nginx 和 nginx-rtmp-module 的源码。 下载地址: http://nginx.org/en/download.html https://github.com/arut/nginx-rtmp-module/tags2)解压、配置 在同一个目录中解压 nginx 和 nginx…...

时间有限,如何精确设计测试用例?5种关键方法

精确设计测试用例能够迅速识别并修复主要缺陷&#xff0c;确保产品质量&#xff0c;降低后期维护成本&#xff0c;并通过专注于核心功能来提升用户体验&#xff0c;为项目的成功奠定坚实基础。若未能精确设计测试用例&#xff0c;可能会导致关键功能测试不充分&#xff0c;使得…...

【算法】图论

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 持续更新中...1、DFS2、BFSN 叉树的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度 3、多源BFS腐烂的苹果 4、拓扑排序 持续更新中…...

ADQ32 5G采集卡

ADQ32是一款高端12位双通道数据采集板&#xff0c;针对高通量科学应用进行了优化。ADQ32具有以下特性: 一个和两个模拟输入通道包括每通道5和2.5 GSPS7GB/s的持续数据传输速率至GPU7GB/秒的持续数据传输速率两个外部触发器通用输入/输出&#xff08;GPIO&#xff09;开放式FPG…...

机器人领域专业名词汇总

1. 电机与驱动 电机类型 DC Motor&#xff08;直流电机&#xff09;&#xff1a;通过直流电源驱动的电机。Stepper Motor&#xff08;步进电机&#xff09;&#xff1a;通过脉冲信号控制旋转角度的电机。Servo Motor&#xff08;伺服电机&#xff09;&#xff1a;带有反馈控制的…...

拆解 “ES 已死“ 伪命题:Agentic RAG 时代搜索引擎的终极形态

作者&#xff1a;来自 Elastic 李捷 xxx&#xff1a;“ES已死&#xff0c;#%#……” 我&#xff1a;&#xff1f;&#xff1f;&#xff1f; 最近&#xff0c;某厂商发了一堆公关文章&#xff0c;翻来覆去地炒作 “ES 已死”&#xff0c;“放弃 ES”。这哪是什么正经的技术文章&…...

eNSP中路由器的CON/AUX接口、GE Combo接口、Mini USB接口、USB接口、WAN侧uplink接口、FE接口、GE接口介绍

路由器常见接口的详细介绍及其应用示例&#xff1a; 1. CON/AUX 接口 全称&#xff1a;Console/Auxiliary&#xff08;控制台/辅助接口&#xff09;作用&#xff1a; CON&#xff08;Console&#xff09;&#xff1a;通过命令行界面&#xff08;CLI&#xff09;直接配置路由器…...

平面的四种方程及一些应用

平面的四种方程及一些应用 点法式方程一般式方程三点式方程截距式方程一些应用已知平面方程&#xff0c;找出平面上不共线的三个点 点法式方程 平面经过点 ( x 0 , y 0 , z 0 ) (x_0,y_0,z_0) (x0​,y0​,z0​)且法向量为 ( a , b , c ) (a,b,c) (a,b,c)&#xff0c;则平面的点…...

记录一个SQL自动执行的html页面

在实际工作场景中&#xff0c;需要运用到大量SQL语句更新业务逻辑&#xff0c;对程序员本身&#xff0c;写好的sql语句执行没有多大问题&#xff08;图1&#xff09;&#xff0c;但是对于普通用户来说还是有操作难度的。因此我们需要构建一个HTML页面&#xff08;图2&#xff0…...

SpringBoot——Maven篇

Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的工具。它具有许多特性&#xff0c;其中一些重要的特性包括&#xff1a; 1. 自动配置&#xff1a;Spring Boot 提供了自动配置的机制&#xff0c;可以根据应用程序的依赖和环境自动配置应用程序的各种组件&#xff…...

数据批处理(队列方式)

数据批处理&#xff08;队列方式&#xff09; public class DataProcessor {private static final int THREAD_COUNT 4;private static final int QUEUE_SIZE 10;private LinkedBlockingQueue<Data> queue new LinkedBlockingQueue<>(QUEUE_SIZE);public DataP…...

从零开始搭建搜索推荐系统(五十四)多路召回之万剑归宗

聊的不止技术。跟着小帅写代码&#xff0c;还原和技术大牛一对一真实对话&#xff0c;剖析真实项目筑成的一砖一瓦&#xff0c;了解最新最及时的资讯信息&#xff0c;还可以学到日常撩妹小技巧哦&#xff0c;让我们开始探索主人公小帅的职场生涯吧&#xff01; &#xff08;PS…...

c++介绍函数指针 十

指针代表内存中地址标识符&#xff0c;变量&#xff0c;数组都是存储内存中的数据。所以可以获得它们的地址&#xff0c;用指针来表示这块内存。 如图输出内存中的地址。 对于一个函数来说&#xff0c;也是内存中存储这段数据&#xff0c;所以我们也可以获取函数的地址。 函数…...

redis数据库

一、redis数据库介绍 NoSQL Not Only SQL 非关系型数据库 1、关系型数据库与非关系型数据库的区别 非关系型数据库性能高、速度快、支持高并发连接 1、非关系型数据库基于内存存储数据 2、摒弃了关系型数据的约束限制 3、采用o1算法进行设计开发 2、作用 关系型数…...

关于 NoC 中数据安全传输的设计与实现的详细介绍

片上网络&#xff08;Network-on-Chip&#xff0c;NoC&#xff09;作为一种新兴的片上通信架构&#xff0c;解决了传统总线架构在大规模集成电路设计中面临的诸多问题。然而&#xff0c;随着芯片系统的复杂性和应用场景的多样化&#xff0c;NoC 中数据安全传输变得至关重要。以…...

OpenGL(4)着色器

文章目录 一、着色器1、什么是着色器&#xff1f;2、着色器类型2.1、顶点着色器&#xff08;Vertex Shader&#xff09;2.2、片段着色器&#xff08;Fragment Shader&#xff09; 3、着色器属性3.1、layout 属性3.2、in 属性3.3、out 属性3.4、总结 4、示例 前言&#xff1a; 在…...

PHP批量去除Bom头的方法

检查的代码&#xff1a; <?php$dir __DIR__; $files new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));foreach ($files as $file) {if ($file->isFile() && pathinfo($file, PATHINFO_EXTENSION) php) {$content file_get_contents(…...

51单片机的keil c51软件安装教程

Keil&#xff08;C51&#xff09;介绍、下载、安装与注册_keil c51-CSDN博客 参考 安装 不一定是这个大小&#xff0c;也可以下载别的版本KEID C51 注册 加入芯片型号 …...

JavaScript基本知识

文章目录 一、JavaScript基础1.变量&#xff08;重点&#xff09;1-1 定义变量及赋值1-2 变量的命名规则和命名规范判断数据类型&#xff1a; 2.数据类型转换2-1 其他数据类型转成数值2-2 其他数据类型转成字符串2-3 其他数据类型转成布尔 3.函数3-1函数定义阶段3-2函数调用阶段…...

导数,积分及常用公式

导数定义&#xff1a; ​ 求导是数学计算中的一个计算方法&#xff0c;它的定义就是&#xff0c;当自变量的增量趋于零时&#xff0c;因变量的增量与自变量的增量之商的极限。在一个函数存在导数时&#xff0c;称这个函数可导或者可微分。可导的函数一定连续。不连续的函数一定…...

鸿蒙应用开发—ZDbUtil高效使用数据库

文章目录 介绍下载安装基本使用注解TableIdColumnOneToOne 使用方法定义实体类初始化数据库并根据被Table注解的类创建表创建表查数据插入数据删除数据清空数据 参考 介绍 ZDbUtil是一款基于SQLite的鸿蒙数据库框架&#xff0c;通过注解标注实体类与属性&#xff0c;让数据更能…...

强化学习(赵世钰版)-学习笔记(7.时序差分学习)

本章是课程算法与方法中的第四章&#xff0c;介绍的时序差分学习算法是基于随机近似方法设计的强化学习方法&#xff0c;也是model-free的方法。 时序差分算法是一种近似估计策略状态值的算法&#xff0c;具体的形式如下&#xff1a; 本质上是在当前t时刻&#xff0c;被访问到的…...

正则表达式入门及常用的正则表达式

正则表达式&#xff08;Regular Expression&#xff0c;简称 Regex&#xff09;是一种强大的文本处理工具&#xff0c;用于匹配、查找和替换字符串中的特定模式。以下是入门指南和常用正则表达式示例&#xff1a; 一、正则表达式入门 1. 基本语法 符号说明示例.匹配任意单个字…...

大白话如何在 Vue 项目中进行路由懒加载?

大白话如何在 Vue 项目中进行路由懒加载&#xff1f; 在 Vue 项目里&#xff0c;路由懒加载是种很实用的技术&#xff0c;它能让你在需要的时候再去加载对应的路由组件&#xff0c;而不是在项目启动时就把所有组件都加载进来&#xff0c;这样能加快项目的启动速度。下面就详细…...

手动实现一个RTTI系统

在 C 中&#xff0c;RTTI&#xff08;Runtime Type Information&#xff0c;运行时类型信息&#xff09;是一组允许程序在运行时获取对象类型信息的机制 。虽然C通过虚接口的方式提供了良好的抽象&#xff0c;但是对于一个复杂的系统&#xff0c;过于依赖抽象而忽略业务的复杂性…...

智能化水利监管:无人机视频在违章行为识别中的应用

随着我国经济社会的快速发展&#xff0c;水利工程建设规模不断扩大&#xff0c;但随之而来的违章建设行为也日益增多。传统的人工巡查方式效率低下&#xff0c;难以满足当前监管需求。无人机技术以其灵活性和高效性&#xff0c;为水利工程建设监管提供了新的解决方案。本文将探…...

力扣练习之确定两个字符串是否接近

目录 题目&#xff1a; 题解&#xff1a; 详细题解 题目&#xff1a; 如果可以使用以下操作从一个字符串得到另一个字符串&#xff0c;则认为两个字符串 接近 &#xff1a; 操作 1&#xff1a;交换任意两个 现有 字符。 例如&#xff0c;abcde -> aecdb 操作 2&#xff1…...

Word 小黑第21套

对应大猫22 设置表格为页面的80%&#xff1a;表布局 -属性 -表格 指定宽度80% 度量单位改成百分比 段落组 -中文版式 在表格上下方留一行空段&#xff08;如果表格太大改一下样式&#xff09;插入横线 边框线 &#xff08;右击横线 -图片 修改样式&#xff09; 段落 -取消对于…...

mingw32编译ffmpeg

ffmpeg https://gitee.com/mirrors/ffmpeg.git 使用msys2的mingw32 pacman -S mingw-w64-x86_64-toolchain compile ./confiure --enable-static --disable-shared --enable-gpl --target-oswin32 mingw32-make -j4 提示编译错误&#xff0c;msys2里面的路径是/d/tools/msys2…...

设计模式C++

针对一些经典的常见的场景, 给定了一些对应的解决方案&#xff0c;这个就叫设计模式。 设计模式的作用&#xff1a;使代码的可重用性高&#xff0c;可读性强&#xff0c;灵活性好&#xff0c;可维护性强。 设计原则&#xff1a; 单一职责原则&#xff1a;一个类只做一方面的…...