深入浅出——MVP模式

article/2025/9/23 3:19:23

由于公司里的架构模式用到MVP,觉得自己还不够熟悉,决定在此理一理,并给大家一起总结下。

一 MVP模式介绍

MVP全称Model View Presenter。
MVP能够有效的降低View的复杂性,避免业务逻辑被塞进View中,防止View的代码变得冗杂。MVP模式会解除View与Model的耦合,同时又带来了良好的扩展性、可测试性,保证了系统的整洁性、灵活性。
肯能对于简单的应用来说MVP稍显麻烦,各种各样接口与概念,使得整个应用充斥着零散的接口,但是对于比较复杂的应用,MVP模式是一种良好的架构模式,它能够非常好的组织应用结构。
MVP结构图
MVP模式可以分离显示层和逻辑层,它们之间通过接口进行通信,降低耦合。理想化的MVP可以实现同一份逻辑代码搭配不同的显示界面,因为它们之间并不依赖与具体,而是依赖与抽象。
其实这边讲View层和Model层分离,也是相比MVC模式有一个很大的改进,我们知道,在Android当中,我们对View的更改需要通过异步来出来,MVP模式切除了View与Model的联系,通过异步的方式来将二者联系在一起,这个分离做的很好。
对于一个可扩展、稳定的应用来说,我们需要定义分离各个层,主要是UI层、业务逻辑层和数据层。毕竟,我们不知道以后还要加入什么逻辑,是从本地数据库检索数据?还是从远程的服务器中?我们的UI、数据库是否会被替换?例如,随着产品的升级,我们的UI可能会被重新设计,若UI发生了变化,此时由于业务逻辑耦合在View中,UI变化导致我们修改新的View控件,此时你就需要到原来的View中抽离具体的业务逻辑,这将是一件令人非常折磨人也易于出错的事,到最终你还是要将业务逻辑抽离开来。
MVP并不是一个标准化的模式,它有很多种实现方式,我们也可以根据自己的需求和自己认为对的方式去修正MVP的实现方式,它可以随着Presenter的复杂层度变化。只要保证我们是通过Presenter将View和Model解耦合、降低类型复杂度、各个模块可以独立测试、独立变化,这就是正确的方向。

二、 MVP模式的三个角色

1.Presenter—–交互中间人
Presenter主要作为沟通View和Model的桥梁,它从Model层检索数据后,返回给View层,使得View和Model之间没有耦合,也将业务逻辑从View角色上抽离出来。
2.View—–用户界面
View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter调用View逻辑接口将结果返回给View元素。
3.Model—–数据的存取
对于一个结构化的APP来说,Model角色主要是提供数据的存取功能。Presenter需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据获取方式的集合。

三、MVP实战举例

讲了那么多概念,这里我们以一个简单的登陆业务逻辑来应用我们的MVP模式。

3.1
首先,我们来看一下整体结构
这里写图片描述

bean层代表的是model层
presenter层代表是处理数据和View层的交互的
view层就是视图层
IUserBiz是一个接口,UserBiz是这个接口的实现类

3.2
首先看下model层
这个类比较简单,就是定义一些变量和方法

public class User {private String usename;private String password;public String getUsename() {return usename;}public void setUsename(String usename) {this.usename = usename;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

接着看下IUserbiz,以及它的实现类IUserBiz,模拟登录操作,等登录操作做完,有一个回调接口来通知登录状态完成

public interface IUserBiz {public void login(String username,String password,OnLoginListener loginListener);
}
public class UserBiz implements IUserBiz {@Overridepublic void login(final String username, final String password, final OnLoginListener loginListener) {//模拟子线程耗时操作Thread thread=new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(2000);}catch (InterruptedException e){e.printStackTrace();}//模拟登陆成功if("aaa".equals(username)&&"123".equals(password)){User user=new User();user.setUsename(username);user.setPassword(password);//回调接口loginListener.loginsuccess(user);}else {loginListener.loginFailed();}}});thread.start();}
}

接着看下View层,里面有很多操作的方法可以去重写,根据自己的经验和严谨的思维去设计这个接口

public interface IUserLoginView {String getUsername();String getPassword();void clearUserName();void clearPassword();void showLoading();void hideLoading();void toMainActivity(User user);void showFailedError();
}

我们继续看下这个的是实现类,也就是我们的activity,在这里实现了我们刚刚定义的方法因为我们用MVP的设计模式,使用的是我们的接口,使我们的代码看上去非常清晰

public class UserLoginActivity extends AppCompatActivity implements IUserLoginView {
...........@Overridepublic String getUsername() {return etUsername.getText().toString();}@Overridepublic String getPassword() {return etPassword.getText().toString();}@Overridepublic void clearUserName() {etUsername.setText("");}@Overridepublic void clearPassword() {etPassword.setText("");}@Overridepublic void showLoading() {mPbLoading.setVisibility(View.VISIBLE);}@Overridepublic void hideLoading() {mPbLoading.setVisibility(View.GONE);}@Overridepublic void toMainActivity(User user) {Toast.makeText(this,user.getUsename()+"login success,to MainActivity",Toast.LENGTH_LONG).show();}@Overridepublic void showFailedError() {Toast.makeText(this,"login failed",Toast.LENGTH_LONG).show();}
}
.....
}

最后,看下我们的Presenter,代表的就是数据和view交互的桥梁,方法比较简单,里面是具体的交互操作,逻辑非常清楚。

public class UserLoginPresenter {
...public void login(){userLoginView.showLoading();//实现接口userBiz.login(userLoginView.getUsername(), userLoginView.getPassword(), new OnLoginListener() {@Overridepublic void loginsuccess(final User user) {//需要在UI线程执行mHandler.post(new Runnable() {@Overridepublic void run() {userLoginView.toMainActivity(user);userLoginView.hideLoading();}});}@Overridepublic void loginFailed() {//需要在UI线程执行mHandler.post(new Runnable() {@Overridepublic void run() {userLoginView.showFailedError();userLoginView.hideLoading();}});}});}}

源码连接:
demo传送门


http://chatgpt.dhexx.cn/article/SLJ5VuAg.shtml

相关文章

MVP模式简单讲解,通俗易懂

了解 MVP 和 MVC 的区别 https://baike.baidu.com/item/MVP/3714550?fraladdin 什么是MVP: MVP 是 MVC 的变种,其实是一种升级。要说 MVP 就要说说 MVC,在 MVC 中 Activity 其实是 View层级,但是通常在使用中 Activity即是View…

MVP框架模式

一、基本概念 MVP是Model-View-Presenter的简称,即模型-视图-表现层的缩写。MVP是由MVC模式进化而来的,MVP改进了MVC中的控制器过于臃肿的问题。 与MVC一样,MVP将应用程序的数据处理、数据显示和逻辑控制分开,用一种业务逻辑、数…

分析几个面试题:==和===;绑定事件;正则表达式

今天也是我学后端的朋友给我发了三个前端的面试题,这里我们试着分析一波。 目录 1、和的含义是什么,又有什么区别呢? (1)赋值: (2)相同: (3)…

前端面经总结

HTML及浏览器 对栅栏布局的理解 栅格化布局中的元素:column列,row行,gutter列之间的距离,container容器 栅格是否可以嵌套 canvas和svg的区别 SVG: SVG 是一种使用 XML 描述 2D 图形的语言。 在 SVG 中,…

前端深入学习

但是面试中必考的点且占比非常大的有前端基础和算法。 决定你是否能拿sp offer(高薪offer)以及是否进名企的是项目和算法。 absolute 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。 元素的位置通过 “left”, “to…

web前端常用词汇

html中的单词 Network [netwɜːk] 网络 General [dʒen(ə)r(ə)l] 一般的,大体的 Request [rɪkwest] 请求 Response [rɪspɒns] 响应 Headers [hedəz] 标题 HyperText [haɪpətekst] 超文本 Transfer [trnsfɝ] 传递 Protocol [prəʊtə…

前端html、css、JavaScript---硬核知识汇总

前端HTML篇 硬核!一篇文章教你阅遍html。 声明:本篇文章只是一个刚开始学习后端开发的菜鸟汇总完成的 JavaWeb学习前导html篇,所以专业性肯定不如前端人员,但用于学习后端开发足够了,刚接触html的童鞋拿来快速了解ht…

前端面试题总结(转载)

DOM结构 —— 两个节点之间可能存在哪些关系以及如何在节点之间任意移动1.DOM中两个节点存在的关系无非3种:1.1.包含与被包含,IE率先引入的contains()方法可检测,例 A.contains(B),即检查节点B是否是节点A的子节点,返回布尔值&…

前端三件套知识点

html 常用插件 文件比较 常用快捷键 ctrl f 查找当前页面的内容 !后按table 或者 html:5 代码模板快捷键 altb调试快捷键 ctrlk ctrlt改颜色主题 altshifta注释快捷键 html基础概念 一、 WEB标准的概念及组成 WEB标准不是某一个标准,而是一系列标准的集合。 …

php前端搜索功能,JavaScript实现前端实时搜索功能的代码分享(图)

这篇文章主要为大家详细介绍了JavaScript实现前端实时搜索功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 大部分页面都具备搜索功能。而作为前端,我们的目的只是将用户输入的内容返回给后台而后呈现反馈数据给用户,具体实…

前端实时搜索功能

** 大部分页面都具备搜索功能。而作为前端&#xff0c;我们的目的只是将用户输入的内容返回给后台而后呈现反馈数据给用户&#xff0c;具体实现如下&#xff1a; ** 1.基本布局&#xff1a; <div class"searcher"><p class"searcher-main">…

适合后端开发人员的html笔记

1html 锚点 <a href"#bottom">跳转到底部</a> <div class"aa"></div> <a href"#" id"bottom">跳转到顶部</a> img 图片标签 h1:一级标题块级元素其他的都是行内元素 img同时具备行内元素和块级…

【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)

文章目录 变量 变量声明的提升数据类型Typeof运算符数据类型转换 表达式与运算符 隐式类型转换toFixed(a)方法保留a位小数关系运算符短路求值流程控制语句 数组函数DOMBOM面向对象 变量 一个变量只定义但没有赋初值&#xff0c;默认值是 undefined定义变量时必须写var&a…

前端面试 汇总整理

-----------------------------------------html css-------------------------------------------- 一.回流与重绘 回流一定引起重绘&#xff0c;重绘不一定回流 1.浏览器渲染机制 1&#xff09;浏览器采用流式布局。 2&#xff09;浏览器将html解析成DOM&#xff0c;css解析成…

JavaWeb——后端开发必备的JavaScript知识

JS学习 1.什么是JavaScript&#xff0c;有什么用&#xff1f; 答&#xff1a;JavaScript是网景公司发明的&#xff0c;运行在浏览器上的脚本语言&#xff0c;简称JS。 补充&#xff1a;网景公司现在没了&#xff0c;被美国在线收购了。 2.在HTML中嵌入JavaScript代码的三种方…

el-input中设置onkeypress事件是否匹配正则表达式显示输入内容的格式

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_BADAO_LIUMANG_QIZHI的博客-CSDN博客_若依前后端分离搭建 设置el-input的onkeypress事件限制输入内容是否匹配正则表达式。 注&#xff1a; 博客&a…

前端开发实习生面试总结

个人感觉面试官对实习生还是很友好的&#xff0c;大部分时候你答不上来都会引导你&#xff0c;最后还会点评你的不足&#xff0c;评价出来的那些问题确实是我自己的短板&#xff01;所以在整个过程中还是学到了很多&#xff01;&#xff01; 本人坐标南京&#xff0c;南京投的相…

datacenter 2

突然综合类又有新的事情了 页面能顺利打开了 但是好像值传不过去 之前不知道为什么输出了三十次 之前是判断两个不为4和200 然后else输出 现在改了之后只输入10次 但是出现通讯错误那个问题

数据中心与云数据中心

数据中心与云数据中心 数据中心&#xff08;DC&#xff0c;DataCenter&#xff09;是指在一个物理空间内实现信息的集中处理、存储、传输、管理等功能&#xff0c;它包括服务器、存储、网络等关键设备和这些关键设备运行所需要的环境因素&#xff0c;如供电、制冷、消防、监控等…

阿里云cassandra数据库datacenter查看

在使用阿里云的cassandra数据库时需要注意的是下图中的数据中心ID对应cassandra中的datacenter&#xff0c;而不是数据中心的名称&#xff01;&#xff01;&#xff01; 即SessionBuilder.withLocalDatacenter方法要使用阿里云cassandra官方文档中的数据中心ID public SelfT w…