MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)
1、MVC
MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展性和模块化。在 MVC 模式中,各组件可以与多种设计模式结合使用,以增强灵活性和可维护性。以下是 MVC 各组件与常见设计模式的关系和作用:
1. Model(模型)
模型代表应用程序的核心数据和业务逻辑。它负责处理数据的存储、操作、验证和规则。
- 设计模式:
- 领域模型(Domain Model):模型中的业务逻辑可以使用领域模型设计模式进行封装,将业务逻辑与数据密切结合。例如,订单、用户、产品等实体类封装业务逻辑。
- 观察者模式(Observer Pattern):当模型数据发生变化时,它可以通知视图更新。模型作为“被观察者”,视图作为“观察者”。观察者模式适合在模型改变时自动更新视图。
- 代理模式(Proxy Pattern):模型中的数据可能通过代理模式进行远程调用或延迟加载,这样可以避免不必要的数据加载,增强性能。
- 数据访问对象模式(DAO Pattern):与数据库交互时,可以通过 DAO 模式封装数据访问逻辑,将数据持久化操作与业务逻辑分离。
2. View(视图)
视图负责显示模型的数据,并将数据呈现给用户。它只关注如何将数据呈现,不负责业务逻辑。
- 设计模式:
- 组合模式(Composite Pattern):如果视图由多个子视图组合而成(如一个页面上有多个部件),组合模式可以将视图组合成一个树形结构,便于处理复杂的视图层次。
- 装饰者模式(Decorator Pattern):通过装饰者模式,可以动态地为视图添加功能或行为,而不改变视图本身的结构。例如,添加滚动条、边框等。
- 观察者模式(Observer Pattern):视图可以订阅模型的变化。当模型发生变化时,视图会自动更新。
3. Controller(控制器)
控制器负责响应用户输入并更新模型。它从视图接收用户的操作请求,并相应地更新模型或改变视图的状态。
- 设计模式:
- 命令模式(Command Pattern):控制器可以通过命令模式封装用户的操作请求,将其转化为命令对象。这样可以灵活处理用户操作,支持操作的撤销、重做等功能。
- 策略模式(Strategy Pattern):控制器可以根据用户的输入或操作选择不同的处理策略。通过策略模式,控制器可以动态改变其行为,增强灵活性。
- 前端控制器模式(Front Controller Pattern):Web 应用中,通常会有一个中央的控制器来处理所有的请求(如 Spring MVC 中的
DispatcherServlet),再根据请求选择具体的处理逻辑。前端控制器模式集中管理所有请求的路由和处理逻辑。
MVC 与各设计模式的结合关系:
- 观察者模式 在 MVC 中非常重要,特别是在模型与视图之间。模型数据变化时自动通知视图更新,解耦了视图和模型之间的直接依赖。
- 命令模式 可以用于控制器,将用户的操作封装为命令对象,使得操作可以记录、撤销或重做。这样特别适合复杂的交互场景。
- 策略模式 可以用在控制器中,根据不同的用户输入或操作选择不同的处理方法。比如在输入不同格式的数据时,选择不同的验证逻辑。
- 装饰者模式 和 组合模式 可以用于视图层,尤其是在复杂的用户界面上,将界面元素进行组合、扩展和装饰,增强视图的灵活性。
- 前端控制器模式 适用于大型 Web 应用中的请求处理,将所有的请求集中管理,并通过路由选择合适的控制器来处理请求。
总结
- MVC 架构模式 本身就可以看作是一种宏观的设计模式,通过将模型、视图和控制器分离,解决了代码结构的分离与解耦问题。
- 设计模式(如观察者、命令、策略、装饰者等)可以在 MVC 的具体实现中进一步增强组件的功能和灵活性。不同设计模式用于解决 MVC 各个组件之间的协作问题,以及增强代码的可扩展性和可维护性。
通过将 MVC 与各种设计模式结合,应用程序可以更加模块化、灵活,并且具备良好的扩展性。
2、MVVM
MVVM(Model-View-ViewModel) 是一种常用于构建用户界面(UI)应用程序的架构模式,它通过Model、View 和 ViewModel 三个部分来分离业务逻辑、用户界面和数据处理,从而实现更清晰的职责划分、提高可维护性以及简化开发过程,特别适合需要数据绑定的场景。
MVVM 各部分职责
-
Model(模型):
- 负责应用程序的业务逻辑、数据访问和处理等。
- 它独立于视图,处理应用程序的核心逻辑。
- 例如数据库操作、API调用、数据验证等都属于Model的职责。
-
View(视图):
- 用户界面部分,用于展示数据并接收用户的输入。
- View层与用户直接交互,负责UI的布局、元素的绘制和用户操作的响应。
- 例如:按钮、文本框、列表等UI元素。
- View不直接与Model交互,它通过ViewModel来获取和更新数据。
-
ViewModel(视图模型):
- 充当View和Model之间的桥梁,负责处理应用逻辑、状态管理、以及数据的双向绑定。
- ViewModel可以从Model获取数据,处理业务逻辑,并将数据传递给View。
- ViewModel通过观察机制通知View数据的变化,同时View也可以通过ViewModel改变Model的数据。
MVVM模式的工作流程
- 双向绑定:MVVM最显著的特点是它支持View和ViewModel之间的双向数据绑定,这意味着当ViewModel中的数据发生变化时,View会自动更新,反之亦然。当用户在UI中做出修改时,这些更改会自动反映到ViewModel中。
- 数据流:
- 用户在View中执行某个操作(如点击按钮)。
- View通知ViewModel,ViewModel会处理该操作并可能更新Model中的数据。
- 当Model的数据变化时,ViewModel会感知到并通知View更新显示。
MVVM的优势
- 分离关注点:通过引入ViewModel,将视图逻辑和业务逻辑分离,减少了代码耦合,提升了代码的可维护性和复用性。
- 双向数据绑定:ViewModel和View之间实现了双向绑定,当Model中的数据更新时,UI会自动更新,这减少了手动同步UI状态的工作量。
- 更容易测试:由于ViewModel不依赖UI框架,单元测试可以集中在ViewModel中的业务逻辑上,而不涉及视图的复杂性。
- 简化复杂UI的管理:对于需要频繁更新UI的应用,MVVM通过ViewModel管理状态,简化了UI更新逻辑。
MVVM的劣势
- 复杂度增加:对于简单的应用,MVVM可能显得过于复杂,ViewModel的引入增加了初期的开发成本。
- 性能问题:大量的双向数据绑定可能在某些场景下带来性能开销,特别是当数据量大或更新频繁时。
- 学习曲线:对于没有使用过MVVM的开发者,理解ViewModel和数据绑定机制可能需要一定的时间和经验。
MVVM的典型应用场景
- 桌面应用程序:特别是WPF(Windows Presentation Foundation)和UWP(Universal Windows Platform)等框架广泛使用MVVM架构。
- 移动应用程序:例如Android开发中的Jetpack架构组件鼓励使用MVVM。
- 复杂的单页应用(SPA):前端框架如Vue.js、Knockout.js等,也实现了类似于MVVM的双向数据绑定模式,适用于需要频繁动态更新的页面。
MVVM实现示例(Java Swing示例)
为了演示MVVM架构模式的工作原理,这里用Java的Swing GUI库创建一个简单的示例,展示如何通过MVVM模式实现一个简单的用户输入和展示。
1. Model:代表业务逻辑和数据
public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
2. ViewModel:负责将Model与View绑定
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;public class UserViewModel {private User user;private PropertyChangeSupport support;public UserViewModel(User user) {this.user = user;this.support = new PropertyChangeSupport(this);}public String getUserName() {return user.getName();}public void setUserName(String name) {String oldName = user.getName();user.setName(name);support.firePropertyChange("userName", oldName, name);}public int getUserAge() {return user.getAge();}public void setUserAge(int age) {int oldAge = user.getAge();user.setAge(age);support.firePropertyChange("userAge", oldAge, age);}public void addPropertyChangeListener(PropertyChangeListener listener) {support.addPropertyChangeListener(listener);}public void removePropertyChangeListener(PropertyChangeListener listener) {support.removePropertyChangeListener(listener);}
}
3. View:负责显示用户界面
import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;public class UserView extends JFrame implements PropertyChangeListener {private JTextField nameField;private JTextField ageField;private JLabel nameLabel;private JLabel ageLabel;private UserViewModel viewModel;public UserView(UserViewModel viewModel) {this.viewModel = viewModel;this.viewModel.addPropertyChangeListener(this);setupUI();}private void setupUI() {nameField = new JTextField(15);ageField = new JTextField(15);nameLabel = new JLabel("Name: ");ageLabel = new JLabel("Age: ");JButton updateButton = new JButton("Update");// 更新按钮的行为,使用ViewModel来处理updateButton.addActionListener(e -> {viewModel.setUserName(nameField.getText());viewModel.setUserAge(Integer.parseInt(ageField.getText()));});// 布局设置setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));add(nameLabel);add(nameField);add(ageLabel);add(ageField);add(updateButton);setTitle("User Info");setSize(300, 200);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}@Overridepublic void propertyChange(PropertyChangeEvent evt) {if ("userName".equals(evt.getPropertyName())) {nameField.setText((String) evt.getNewValue());} else if ("userAge".equals(evt.getPropertyName())) {ageField.setText(evt.getNewValue().toString());}}public static void main(String[] args) {User user = new User("John Doe", 30);UserViewModel viewModel = new UserViewModel(user);UserView view = new UserView(viewModel);view.setVisible(true);}
}
总结
- 在这个例子中,Model层
User负责保存用户的数据,ViewModel层UserViewModel负责处理与Model的数据交互,View层UserView负责展示用户界面并通过PropertyChangeListener绑定ViewModel的数据变化。 - 通过MVVM架构,View与Model之间的依赖被削弱,ViewModel管理了数据绑定的逻辑,使代码更加模块化、易于维护。
3、对比
**MVVM(Model-View-ViewModel)和MVC(Model-View-Controller)**都是流行的架构模式,用于构建可维护的用户界面应用程序。两者有相似的目标,都是为了分离关注点,但在实现和使用上各有优缺点。
MVC与MVVM对比
1. MVC模式
- Model:表示数据和业务逻辑。它独立于用户界面,并且不直接与View交互。
- View:负责显示Model的数据。View从Controller获取指令,更新界面。
- Controller:充当Model和View之间的中介,处理用户输入并根据需要更新Model或View。
MVC的优点
- 清晰的职责分离:Model、View、Controller各自负责独立的部分,降低代码耦合度。
- 简单直观:适用于中小型应用,结构简单,易于理解。
- 灵活性:Controller可以根据不同的输入调整Model或View的行为,拥有较高的灵活性。
- 历史悠久:MVC模式已经被广泛使用,很多开发框架支持这种模式,社区和资源丰富。
MVC的缺点
- Controller复杂度:随着系统规模增大,Controller的职责会变得复杂,需要处理大量逻辑和不同组件之间的交互,容易出现“肥大控制器”问题。
- 双向绑定缺乏:MVC模式中的View和Model之间缺乏内置的双向绑定机制,View的状态更新需要手动处理,增加了管理的复杂度。
- 测试困难:View和Controller之间的强耦合可能导致在进行单元测试时,测试的范围过大,不利于细粒度的测试。
2. MVVM模式
- Model:和MVC中的Model类似,负责业务逻辑和数据处理。
- View:负责用户界面和用户交互。
- ViewModel:负责管理Model和View之间的数据和操作逻辑。ViewModel处理UI逻辑,且与View双向绑定,直接与View进行数据通信。
MVVM的优点
- 双向数据绑定:MVVM模式支持双向数据绑定,ViewModel中的数据发生变化时,View会自动更新,反之亦然,减少了手动更新UI的工作量。
- 弱化Controller的职责:MVVM将控制逻辑放到ViewModel中,避免Controller过度复杂化,简化了业务逻辑的实现。
- 更容易测试:由于ViewModel不依赖于UI框架,逻辑集中在ViewModel中,且没有直接操作View,单元测试更容易实现。
- 可复用性和扩展性:ViewModel可以根据不同的需求和上下文场景进行复用和扩展,便于维护。
- 解耦性强:View和Model之间通过ViewModel解耦,降低了依赖性,尤其在复杂UI下,灵活性更高。
MVVM的缺点
- 复杂度更高:对于简单应用来说,MVVM可能显得过于复杂。引入ViewModel层会增加初期开发成本和学习曲线。
- 性能问题:在大量双向数据绑定的场景下,频繁的UI更新和数据变化可能导致性能问题,尤其在数据绑定的实现较为繁重时。
- 学习成本:如果开发者不熟悉MVVM,尤其是双向绑定的机制,可能需要较长时间来适应该模式的使用。
MVC 与 MVVM 的优缺点对比
| 比较项 | MVC | MVVM |
|---|---|---|
| 复杂性 | 相对较低,适合简单或中等复杂应用 | 更高复杂度,适合大型复杂应用 |
| 职责分离 | 清晰,但Controller易变得复杂 | 职责更清晰,View和Model完全解耦 |
| 数据绑定 | 没有内置数据绑定 | 内置双向数据绑定,UI更新自动化 |
| 代码复用性 | Controller中的逻辑难以复用 | ViewModel中的逻辑易于复用 |
| 测试友好性 | Controller和View耦合较多,测试困难 | ViewModel易于测试 |
| 学习曲线 | 相对简单,易于上手 | 学习曲线较陡,双向绑定需要理解 |
| 性能表现 | UI更新手动控制,性能稳定 | 频繁数据绑定可能影响性能 |
适用场景
-
MVC 适用场景:
- 中小型应用:应用逻辑较为简单,界面与业务逻辑的交互不复杂。
- 经典Web应用:很多传统的Web应用使用MVC架构,页面跳转和视图更新相对简单。
-
MVVM 适用场景:
- 大型复杂应用:如桌面应用或移动应用,特别是需要频繁更新UI且有复杂数据展示和交互的系统。
- 双向绑定需求强的场景:如需要大量动态数据展示的应用,如仪表盘或数据监控系统。
总结
- MVC:更适合中小型应用,易于理解和实现。但随着复杂度增加,Controller部分可能变得笨重,代码复用性和可维护性较差。
- MVVM:通过双向数据绑定,使得UI和逻辑层解耦,适合复杂场景,尤其是大量用户交互的应用。虽然复杂度较高,但更适合大型系统。
相关文章:
MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)
1、MVC MVC(Model-View-Controller) 是一种常用的架构模式,用于分离应用程序的逻辑、数据和展示。它通过三个核心组件(模型、视图和控制器)将应用程序的业务逻辑与用户界面隔离,促进代码的可维护性、可扩展…...
【H2O2|全栈】关于HTML(4)HTML基础(三)
HTML相关知识 目录 HTML相关知识 前言 准备工作 标签的具体分类(三) 本文中的标签在什么位置中使用? 列表 编辑编辑 有序列表 无序列表 自定义列表 表格 拓展案例 预告和回顾 后话 前言 本系列博客将分享HTML相关知识点…...
关于找不到插件 ‘org.springframework.boot:spring-boot-maven-plugin:‘的解决方案
找到项目结构后,点击库,全选所有后点击应用即可...
深入RabbitMQ世界:探索3种队列、4种交换机、7大工作模式及常见概念
文章目录 文章导图RabbitMQ架构及相关概念四大核心概念名词解读 七大工作模式及四大交换机类型0、前置了解-默认交换机DirectExchange1、简单模式(Simple Queue)-默认DirectExchange2、 工作队列模式(Work Queues)-默认DirectExchange3、发布/订阅模式(Publish/Subscribe)-Fano…...
将目标检测模型导出到C++|RT-DETR、YOLO-NAS、YOLOv10、YOLOv9、YOLOv8
点击下方卡片,关注“小白玩转Python”公众号 最近,出现了更新的YOLO模型,还有RT-DETR模型,这是一个声称能击败YOLO模型的变换器模型,我想将这些模型导出并进行比较,并将它们添加到我的库中。在这篇文章中&a…...
【Windows】解决新版 Edge 浏览器开机自启问题(简单有效)
文章目录 1.前言2.查找资料3.查找方法4.解决办法1.点击浏览器的三个...,然后点击设置2.选择【开始、主页和新建标签页】选项卡,然后关闭【Windows设备启动时】 结语 参考文章: 解决新版 Edge 浏览器开机自启问题(简单有效…...
如何给3D人物换衣服CC4
1.导入人物 2.设置人物Apose 3.导入衣服 create -> accessory 选择fbx文件 设置衣服的大小和位置。 4.绑定衣服 设置衣服的权重 添加动作就可以看效果了。...
如何对列表、字符串进行分组
如何对列表、字符串进行分组 1、效果 2、代码 使用python自带库collections中的Counter函数即可实现 代码如下: # -*- coding: utf-8 -*-""" @contact: @file: test.py @time: 2024/9/8 11:18 @author: LDC """ from collections import Co…...
【GEE代码实例教程详解:NDVI时间序列趋势分析】
GEE(Google Earth Engine)是一个强大的云计算平台,用于处理和分析大规模地球科学数据集。以下是一个关于如何使用GEE进行NDVI(归一化植被指数)时间序列趋势分析的详细教程。 一、引言 NDVI时间序列趋势分析是一种统计…...
51单片机-DS1302(RTC实时时钟芯片)
数据手册在主页资源免费贡献 开发板芯片数据手册 https://www.alipan.com/s/nnkdHhMGjrz 提取码: 95ik 点击链接保存,...
FreeRTOS学习笔记—②RTOS的认识及任务管理篇
由于正在学习韦东山老师的RTOS课程,结合了网上的一些资料,整理记录了下自己的感悟,用于以后自己的回顾。如有不对的地方请各位大佬纠正。 文章目录 一、RTOS的优势二、RTOS的核心功能2.1 任务管理2.1.1 任务的创建2.1.2 任务的删除*2.1.3 任…...
【C++从练气到飞升】22---C++中的异常
🎈个人主页:库库的里昂 ✨收录专栏:C从练气到飞升 🎉鸟欲高飞先振翅,人求上进先读书🎉 目录 ⛳️推荐 一、C语言传统的处理错误的方式 二、C异常 三、异常的使用 3.1 异常的抛出和捕获 3.1.1 异常的抛…...
前端:HTML、CSS、JS、Vue
1 前端 内容概要 了解前端三件套(HTML、CSS、JS)在前端所起的作用掌握HTML标签的功能,掌握重要标签(a标签,form标签)了解CSS了解JS的基础语法掌握Vue的基础语法重点掌握Vue项目怎么启动项目掌握前后端分离是什么。前端做什么事情,后端做什么…...
RocksDB简介
一、RocksDB是什么 常见的数据库如 Redis Mysql Mongo 可以单独提供网络服务RocksDB提供存储服务,是一个嵌入式KV存储引擎 Rocksdb没有server code,用户需要自己实现server的部分来得到c-s架构的数据库。二、RocksDB的诞生 基于flash存储和ssd普及,网络latency在query worklo…...
[VC] Visual Studio中读写权限冲突
前置场景: 编译没有报错,但是运行提示 内存异常: 情景1: 如下代码运行异常,提示引发了异常:写入权限冲突。*** 是 0xFFFFF..... char* str (char*)malloc(10);str[0] 0x30; 解决方案:要包含头…...
ChatGPT3.5/4.0新手使用手册,国内中文版使用教程
引言 欢迎使用ChatGPT!无论你是刚开始接触AI聊天机器人,还是已经有了一些使用经验,这篇新手使用手册将帮助你快速上手,并且从ChatGPT中获得最优的体验。本文主要聚焦于提示词(Prompt)的使用教学࿰…...
基于MicroPython的ESP8266与超声波传感器设计方案
基于MicroPython的ESP8266与超声波传感器的设计方案: 一、硬件准备 1. ESP8266 开发板(如NodeMCU) 2. 超声波传感器(如HC-SR04) 3. 杜邦线若干 二、硬件连接 1. 将超声波传感器的VCC引脚和ESP8266 的3.3V引脚,分别连接5V和3.3V电…...
仿华为车机UI--图标从Workspace拖动到Hotseat同时保留图标在原来位置
基于Android13 Launcher3,原生系统如果把图标从Workspace拖动到Hotseat里则Workspace就没有了,需求是执行拖拽动作后,图标同时保留在原位置。 实现效果如下: 实现思路: 1.如果在workspace中拖动,则保留原来“改变图标…...
C++ 中的 override 和 overload的区别
目录 1.Overload(重载) 2.override(重写) 3.override 和 overload 的根本区别 4.override 和 overload 的实际应用 5.override 和 overload 的常见误区 6.总结 1.Overload(重载) 定义:在同一个作用域内,可以声明几个功能类似的函数名相同的函数&am…...
spring boot3框架@Validated失效
项目中使用的springboot3.2.1,在使用Validated校验controller里参数时始终不生效;在网上查了相关资料,添加了spring-boot-starter-validation依赖但还是不行 经过层层调试,终于发现问题; springboot3添加Validated后校验的是 ja…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
