前端---对MVC MVP MVVM的理解
就需要从前端这些年的从无到有、从有到优的变迁过程讲一下。
1. Web1.0时代
在web1.0时代并没有前端的概念,开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常用多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、c#/Java/PHP代码,系统整体架构可能是这样子的:
我们可以看到服务端是比较重的,有一块既在客户端又在服务端,jsp是在我们server端生成的,然后他调用我们的service获取数据,然后在jsp页面进行封装,最后再把html前端的代码混成一个直接返回给前端。
所以我们可以看到这种架构的模式比较简单,而且很快捷。
但是缺点也很明显:jsp代码难以维护(前端代码和后端代码是混在一起的,如果业务逻辑复杂一些这个代码应该是非常庞大的)
2. MVC开发模式
为了让开发更加的快捷,代码更容易维护,前后的职责更清晰一些(不要把代码混在一起),就衍生出来了MVC开发模式和框架,前端展示以模型的形式出现。典型的框架就是Spring、Structs、Hibernate。整体框架如图所示:
他们的目标就是把我们的视图、数据和业务逻辑控制分层,这样代码也就分层了。
使用这种分层架构、职责清晰,代码容易维护。但是这里的MVC仅限于后端,前后端形成了一定的分离,前端只完成了后端开发中的view层。
那时候的前端程序员只是写一些前端页面和少量的js代码进行交互,但是仅限于静态页面,没有数据,然后再把这个页面交给后端程序员,后端再拿模版语法对他进行动态化的改造。
但是这种模式也存在着一些问题:
- 前端页面开发效率不高(主要把图变成静态页面然后交给后端)
- 前后端职责不清
3. Web 2.0
自从Gmail的出现,ajax技术风靡全球,有了ajax之后,前后端的职责就更加清晰了。因为前端可以通过ajax与后端进行数据交互,因此整体的架构图就变成了下幅图:
通过ajax与后台服务器进行数据交互,前端开发人员只需要开发页面这部分内容,数据可由后台进行提供。而且ajax可以使页面实现部分刷新,减少了服务端负载和流量消耗,用户体验更好。这时候才有了专职的前端工程师。同时前端的类库也慢慢的发展,最著名的就是jQuery了。
当然此架构也存在一些问题:缺乏可行的开发模式承载更复杂的业务需求,页面内容都糅杂在一起,一旦应用规模增大就难以维护。因为前端的MVC也随之而来。
4.前后端分离后的架构演变–MVC、MVP、MVVM
1. MVC
前端的MVC与后端的类似,具备着View、Controller和Model
Model:负责保存应用逻辑,与后端数据进行同步(专门用来封装和处理数据的)
Controller:负责业务逻辑,根据用户行为对Model数据进行修改(专门来处理请求的,1.接收参数 2.调用service层代码 3.控制页面跳转)
View:负责视图展示,将model中的数据可视化出来 好处:奇强调责任分离,方便维护代码
三者形成了一个模型:
这样的模型在理论上是可行的,但是在开发的过程中并不会这么操作。因为开发过程不灵活,例如:一个小小的事件操作都必须经过这么一个流程,那么开发就不在便捷了。
在实际场景中,我们往往会看到另外一种模式,如图:
这种模式在开发中更加的灵活,backbone.js框架就是这种模式。
但是这种灵活可能导致严重的问题:
- 数据流混乱(数据再发生变化时不知道是谁变的,在做维护的时候找问题就不好查)
- View比较庞大,但是Controller比较单薄(一些简单的数据监听,然后直接调用Model层的更改逻辑,可有可无):由于很多的开发者都会在view中写一些逻辑代码,逐渐的就导致view中的内容越来越庞大,而controller变得越来越单薄。
既然有了缺陷就会有变革,前端的变化中似乎少了MVP的这种模式,是因为Angular早早地将MVVM框架模式带入了前端,MVP模式虽然在前端开发模式中不常见,但是在安卓等原生开发中,开发者还是会考虑它的。
2.MVP
MVP模式与MVC很接近,P指的是presenter,我们可以理解为一个中间人,他负责着View和Model之间的数据流动,防止二者之间的直接交流,我们可以看一下图示:
我们可以看到presenter负责和Model进行双向交互,还和View进行双向交互。这种交互方式相对于MVC来说少了一些灵活,View变成了被动视图,并且本身变得很小。虽然他分离了View和Model,但是应用逐渐变大之后导致presenter的体积变大,难以维护。如果想解决这个问题,我们可以从MVVM的思想中找到答案。
3.MVVM(Model-View-ViewModel)
ViewModel可以理解成是Presenter的进阶版
M(model):专门来准备数据的
V(View):展示页面
VM(ViewModel):视图和模型(视图和模型的转换):他是DOM监听器,监听着页面dom节点的变化,当页面DOM节点发生改变的时候,数据也会发生对应的改变
双向绑定机制:
- ViewModel通过实现一套数据响应式机制自动响应Model中数据的变化(绑定数据:当model数据发生变化的时候,对应的界面也会发生改变)
- 同时ViewModel会实现一套更新策略自动将数据变化转换成视图更新(DOM监听器,监听着页面dom节点的变化,当页面DOM节点发生改变的时候,数据也会发生对应的改变)
- 实现数据绑定的方法有多种,常见的有观察者模式和发布-订阅模式。
通过事件监听响应View中用户交互修改Model数据
这样在ViewModel中就减少了大量的DOM操作代码
MVVM在保持View和Model松耦合的同时,还减少了维护他们关系的代码,使用户专注于业务逻辑,兼顾开发效率和可维护性。
5.总结
- 这反映了前端领域的发展进程,这三者都是框架模式,它们设计的目标都是为了分层:解决Model和Viev的耦合问题。
- MVC模式出现较早主要应用在后端,如Spring MVC、ASP.NET MVC等,在前端领域的早期也有应用,如Backbone.js,它的优点是分层清晰,缺点是数据流混乱,灵活性带来的维护性问题。
- MVP模式在是MVC的进化形式,Presenter作为中间层负责MV通信,解决了两者耦合问题,但P层过于臃肿会导致维护问题。
-MVVM模式在前端领城有广泛应用,它不仅解决MV耦合问题,还同时解决了维护两者映射关系的大量繁杂代码和DOM操作代码,在提高开发效率、可谈性同时还保持了优越的性能表现。
相关文章:

前端---对MVC MVP MVVM的理解
就需要从前端这些年的从无到有、从有到优的变迁过程讲一下。 1. Web1.0时代 在web1.0时代并没有前端的概念,开发一个web应用多数采用ASP.NET/Java/PHP编写,项目通常用多个aspx/jsp/php文件构成,每个文件中同时包含了HTML、CSS、JavaScript、…...

深度学习 --- VGG16能让某个指定的feature map激活值最大化图片的可视化(JupyterNotebook实战)
VGG16能让某个指定的feature map激活值最大化图片的可视化 在前面的文章中,我用jupyter notebook分别实现了,预训练好的VGG16模型各层filter权重的可视化和给VGG16输入了一张图像,可视化VGG16各层的feature map。深度学习 --- VGG16卷积核的可…...

1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据
1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据 1、时间:1990-2022年 2、来源:城市统计年鉴 3、指标:年度、城市名称、城市代码、城市类别、省份标识、省份名称、国内生产总值/亿元、第一产业占GDP比重(%)、第二产业占GDP比重(%)、第…...

c++ 原型模式
文章目录 什么是原型模式为什么要使用原型模式使用场景示例 什么是原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象,简单理解就是“克隆指定对象” 为什么要使用原型模式 原型模式(Prototype Pattern)是…...
论tomcat线程池和spring封装的线程池
Tomcat 中的线程池是什么? 内部线程池:Tomcat 确实有一个内部的线程池,用于处理 HTTP 请求,通常是org.apache.tomcat.util.threads.ThreadPoolExecutor 类的实例。这个线程池专门用于处理进入的 HTTP 请求和发送响应。可以通过 T…...

阿里P7大牛整理自动化测试高频面试题
最近好多粉丝咨询我,有没有软件测试方面的面试题,尤其是Python自动化测试相关的最新面试题,所以今天给大家整理了一份,希望能帮助到你们。 接口测试基础 1、公司接口测试流程是什么? 从开发那边获取接口设计文档、分…...
vue如何实现路由缓存
(以下示例皆是以vue3vitets项目为例) 场景一:所有路由都可以进行缓存 在渲染路由视图对应的页面进行缓存设置,代码如下: <template><router-view v-slot"{ Component, route }"><transiti…...
基于Openjdk容器打包运行jar程序
文章目录 应用场景基于Openjdk容器打包运行jar程序1.编译项目成jar包2.构建Dockerfile文件精简版-含jar包精简版-不含jar包带注释版-含jar包 3.编译Dockerfile成镜像。4.运行镜像: 应用场景 部署多版本jdk的应用程序。 基于Openjdk容器打包运行jar程序 1.编译项目…...

DNN学习平台(GoogleNet、SSD、FastRCNN、Yolov3)
DNN学习平台(GoogleNet、SSD、FastRCNN、Yolov3) 前言相关介绍1,登录界面:2,主界面:3,部分功能演示如下(1)识别网络图片(2)GoogleNet分类…...
HTTP协议(超文本传输协议)
HTTP请求消息 http请求消息组成: 请求行 :包含请求的方法 操作资源的地址 协议的版本号 http请求方法: GET:从服务器获取资源 POST:添加资源信息 PUT:请求服务器更新资源信息 DELETE:请…...
FFmpeg的日志系统(ubuntu 环境)
1. 新建.c文件 vim ffmpeg_log.c2. 输入文本 #include<stdio.h> #include<libavutil/log.h> int main() {av_log_set_level(AV_LOG_DEBUG);av_log(NULL,AV_LOG_INFO,"hello world");return 0; }当log level < AV_LOG_DEBUG 都可以印出来 #define A…...

浅析VO、DTO、DO、PO
一、概念介绍 POJO(plain ordinary java object) : 简单java对象,个人感觉POJO是最常见最多变的对象,是一个中间对象,也是我们最常打交道的对象。一个POJO持久化以后就是PO,直接用它传递、传递…...

android kotlin基础复习 enum
1、kotlin中,关键字enum来定义枚举类型。枚举类型可以包含多个枚举常量,并且每个枚举常量可以有自己的属性和方法。 2、测试代码: enum class Color{RED,YELLOW,BLACK,GOLD,BLUE,GREEN,WHITE }inline fun <reified T : Enum<T>>…...

个股场外期权怎么交易?场外期权交易流程是怎样的?
今天带你了解个股场外期权怎么交易?场外期权交易流程是怎样的?个股场外期权是一种非标准化的期权合约,通常在场外市场(OTC市场)由金融机构和投资者之间进行交易。 场外个股期权主要功能 风险管理: 帮助投…...

企业选ETL还是ELT架构?
作为数据处理的重要工具,ETL工具被广泛使用,同时ETL也是数据仓库中的重要环节。本文将从解释ETL工具是怎么处理数据,同时介绍ELT和ETL工具在企业搭建数据仓库的重要优势。 一、什么是ETL? ETL是Extract-Transform-Load的缩写,将…...
【Spring Boot 3】【Web】同时启用 HTTP 和 HTTPS
【Spring Boot 3】【Web】同时启用 HTTP 和 HTTPS 背景介绍开发环境开发步骤及源码工程目录结构背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是…...

【Android】最好用的网络库:Retrofit
最好用的网络库:Retrofit 文章目录 最好用的网络库:RetrofitRetrofit的基本用法Retrofit的使用逻辑Retrofit的基本操作处理复杂的接口地址类型进阶删除提交header中指定参数 Retrofit构建器的最佳写法Retrofit的使用封装 用户网络请求的接口配置繁琐&…...

SpringBoot自动化配置原理
SpringBoot自动化配置原理 01-SpringBoot2高级-starter依赖管理机制 目的:通过依赖能了解SpringBoot管理了哪些starter 讲解: 通过依赖 spring-boot-dependencies 搜索 starter- 发现非常多的官方starter,并且已经帮助我们管理好了版本。 …...

2024级新生数组字符串专题题解
一、题解: 1.A-[NOIP2005]校门外的树_24级新生数组字符串训练题 (nowcoder.com) 这题常见的解法有两种: 第一种是这道题我们可以直接按照题目意思枚举 #include<bits/stdc.h> #define int long long using namespace std;int road[10010];sig…...
C++学习 虚函数,容器
一、虚函数 虚函数是C中的一种函数,允许子类重写父类中的函数,以便在运行时通过基类指针或引用调用子类的函数实现。虚函数的主要作用是实现多态性,这使得基类指针或引用可以根据实际指向的对象类型调用不同的函数实现。具体用法 虚函数的声…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...