了解MVC、MVP、MVVM模式

前言

  • Android开发中,当你梳理完需求后,你要做的并不是马上写下你的第一行代码,而是需先设计好整个项目的技术框架
  • 今天,我将全面介绍Android开发中主流的技术框架MVCMVP 与 MVVM模式,并实例讲解MVP模式,希望您们会喜欢。

目录

示意图


1. 为什么要进行技术框架的设计

  • 模块化功能
    使得程序模块化,即:内部的高聚合模块之间的低耦合
  • 提高开发效率
    开发人员只需专注于某一点(视图显示、业务逻辑 / 数据处理)
  • 提高测试效率
    方便后续的测试 & 定位问题

切记:不要为了设计而设计,否则反而会提高开发量

示意图


2. Android开发主流的技术框架

  • 主要有MVCMVPMVVM 3种模式
  • 下面,我将详细 & 具体的介绍上述3种模式

2.1 MVC模式

  • 角色说明

示意图

  • 模式说明

示意图

  • 该模式存在的问题:Activity责任不明、十分臃肿
    Activity由于其生命周期的功能,除了担任View层的部分职责(加载应用的布局、接受用户操作),还要承担Controller层的职责(业务逻辑的处理)
    随着界面的增多 & 逻辑复杂度提高,Activity类的代码量不断增加,越加臃肿

2.2 MVP模式

  • 出现的原因
    为了解决上述MVC模式存在的问题,把分离Activity中的View层 和 Controller层的职责,从而对Activity代码量进行优化、瘦身,所以出现了MVP模式

  • 角色说明

示意图

  • 模式说明

示意图

  • 优点:(对比MVC模式)
  1. 耦合度更低:通过Presenter实现数据和视图之间的交互,完全隔离了View层与Mode层,二者互不干涉

避免了ViewModel的直接联系,又通过Presenter实现两者之间的沟通

  1. Activity代码变得更加简洁:简化了Activity的职责,仅负责UI相关操作,其余复杂的逻辑代码提取到了Presenter层中进行处理

2.3 MVVM

为了更加分离M、V层,更加释放Activity的压力,于是出现了MVVM模式

  • 定义
    VM层:ViewModel,即 View的数据模型和Presenter的合体

基本上与 MVP 模式完全一致,将逻辑处理层 Presenter 改名为 ViewModel

  • 模式说明

示意图

  • 优点
    使得视图层(View)& 控制层(Controller)之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力

本文主要讲解MVC和MVP模式,不过多阐述MVVM模式.


3. MVC、MVP模式的区别

示意图


4. 三种模式出现的初衷

  • MVC模式的出现
    为解决程序模块化问题,于是MVC模式出现了:将业务逻辑、数据处理与界面显示进行分离来组织代码,即分成M、V、C层;
  • MVP模式的出现
    但M、V层还是有相互交叉、隔离度不够,同时写到Activity上使得Activity代码臃肿,于是出现了MVP: 隔离了MVC中的 M 与 V 的直接联系,将M、V层更加隔离开来,并释放了Activity的压力;
  • MVVM模式的出现
    为了更加分离M、V层,更加释放Activity的压力,于是出现了MVVM: 使得V和M层之间的耦合程度进一步降低,分离更为彻底,同时更加减轻了Activity的压力。

下面,我将详细讲解一下最常用的MVP模式的核心思想 & 使用


5. MVP模式详解

此处主要详细分析MVP模式的核心思想,并实例说明。

5.1 核心思想

把Activity里的逻辑都抽离到ViewPresenter接口中去 & 由具体的实现类来完成。具体实现思路如下:

  1. Activity中的UI逻辑抽象成View接口 & 由具体的实现类来完成
  2. 把业务逻辑抽象成Presenter接口 & 由具体的实现类来完成
  3. Model类还是原来MVC模式的Model

5.2 实现步骤

MVP模式的UML

示意图

通过UML图可看出,使用MVP模式的步骤如下:

示意图

5.3 实例讲解

本节通过一个 英语词典app实例 讲解 MVP模式具体的实现

前言:工程项目的列表架构

MVP技术架构的项目结构非常清晰:把MVP层分别分为三个文件夹:ModelViewPresenter,每个文件下分别是对应的接口和实现的类

其中Model层的fanyi类是作为实现用GSON解析JSON信息的一个JavaBean

步骤1:设置View层(IView接口 & 实现类)

/**
  * View接口:IfanyiView
  * 需定义在实现类中需要用到的方法
  */
 
  public interface IfanyiView {    
 
    void init();//初始化   
    void SetInfo(String str); //输出翻译信息    
    void SetError(); //输出出错信息
 
    }
 
/**
  * View实现类:MainActivity类
  * 注:由于MainActivity是对应View层的实现类,所以要实现View层的接口
  */
 
  public class MainActivity extends AppCompatActivity implements IfanyiView {   
 
      private EditText et;    
      private TextView tv;    
      CidianPresenter cidianPresenter;  // 声明了Presenter对应类 
 
        @Override    
        protected void onCreate(Bundle savedInstanceState) { 
               super.onCreate(savedInstanceState); 
               setContentView(R.layout.activity_main);        
                  // 实例化P对应类的对象和findView        
                   init();        
                // 接受用户的输入  
                findViewById(R.id.btnfanyi).setOnClickListener(new View.OnClickListener() {      
              
                    @Override            
                    public void onClick(View v) {                
                    //将View层获得的数据传入Presenter层 ,注意还要传递MainActivity
                          cidianPresenter.InputToModel(et.getText().toString(), MainActivity.this);            
                         }        
                      });    
                    }    
 
                    @Override    
                    public void init(){        
                    //实例化P类的对象和findView        
                      cidianPresenter = new CidianPresenter(this);        
                      et = (EditText) findViewById(R.id.editText);        
                      tv = (TextView) findViewById(R.id.tv);    
                    }
 
                    @Override  
                    //输出出错信息   
                    public void SetError() {        
                      tv.setText("查询不成功,请检查网络");    
                     }
 
                    //输出翻译信息
                    @Override    
                    public void SetInfo(String str){        
                    tv.setText(str);    
                     }
                    }
 
  // 从上述代码可看出,MainActivity只做了FindView、setListener的工作(包含了cidianPresenter),简洁清爽!

步骤2:设置Presenter层(创建IPresenter接口&实现类)

/**
  * Presenter接口:ICidianPresenter
  * 需定义在实现类中需要用到的方法
  */
  public interface ICidianPresenter {    
      
     void InputToModel(String input,Context context); // 将View层获得的数据传入Model层
 
  }
 
 
/**
  * Presenter层的实现类:CidianPresenter类
  * 注:由于CidianPresenter是对应Presenter层的实现类,所以要实现Presenter层的接口
  */
  public class CidianPresenter implements onfanyiListener,ICidianPresenter {    
      // 1. 声明View层对应接口、Model层对应的类    
      IfanyiView fyV;    
      fanyimodel fanyimodel;    
 
      // 2. 重构函数,初始化View接口实例、Model实例    
      public  CidianPresenter(IfanyiView fyV){        
          this.fyV = fyV;        
          fanyimodel = new fanyimodel();   
       }  
 
      // 3.将View层获得的数据传入Model层,注意要传递this.当前类
          @Override    
          public void InputToModel(String input, Context context){  
 
          fanyimodel.HandleData(input, context, this);    
 
          }    
          // 回调函数,调用UI更新  
          @Override    
          public void onSuccess(String str) {        
              fyV.SetInfo(str);    }  
          // 回调函数,调用UI输出出错信息
          @Override    
          public void onError() {        
              fyV.SetError();    } 
          }
 
      // 注:
      // a. 保留IfanyiView的引用,就可直接在CidianPresenter当前类进行UI操作而不用在Activity操作
      // b. 保留了Model层的引用就可以将View层的数据传递到Model层

步骤3:Model层(Model层接口 & 实现类)

/**
  * Model层接口:Ifanyi
  * 需定义在实现类中需要用到的方法
  */
  public interface Ifanyi {  
 
    void HandleData(String input,Context context,final onfanyiListener listener);    
    String fanyiToString(fanyi fy);
 
  }
 
/**
  * Model层的实现类:fanyiModel类
  * 注:由于fanyiModel是对应Model层的实现类,所以要实现Model层的接口
  */
  public class fanyimodel implements Ifanyi {
 
      private fanyi fy = new fanyi();
 
      public void HandleData(String input,Context context,final onfanyiListener listener){
 
          // 使用Volley框架来实现异步从网络的有道API获取翻译数据
          RequestQueue mQueue = Volley.newRequestQueue(context);
          StringRequest stringRequest = new StringRequest("http://fanyi.youdao.com/openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q="+input, new Response.Listener<String>() {
              @Override
              public void onResponse(String s) {
 
                  // 用Gson方式解析获得的json字符串
                  Gson gson = new Gson();
                  fy = gson.fromJson(s.trim(),fy.getClass());
 
                  // 回调监听器的函数把处理数据后的结果(翻译结果)返回给Presenter层
                  listener.onSuccess(fanyiToString(fy));
              }
          }, new Response.ErrorListener() {
              @Override
              public void onErrorResponse(VolleyError volleyError) {
                  listener.onError();
              }
          });
          mQueue.add(stringRequest);
      }
 
      public String fanyiToString(fanyi fy){
          // 处理解析后的json数据,转成UI输出的字符串
          String strexplain = "解释:";
          String strphonetic = "发音:";
          String strweb = "网络释义:";
          if (fy.basic == null){return "你所查找的还没有准确翻译";}
          for (int i = 0; i<fy.basic.explains.length; i++){
              strexplain +=fy.basic.explains[i]+"\n";
              if (i != fy.basic.explains.length-1 )
              {strexplain +="\t\t\t\t";}
          }
          strphonetic += fy.basic.phonetic +"\n";
          for (int i = 0; i<fy.web.size(); i++){
              for(int j = 0; j<fy.web.get(i).value.length;j++)
              {
                  strweb += fy.web.get(i).value[j]+",";
              }
              strweb += fy.web.get(i).key+"\n";
              strweb += "\t\t\t\t\t\t\t";
          }
          return strexplain+"\n"+strphonetic+"\n"+strweb;
      }
  }
 

至此,关于MVP模式的实例讲解,讲解完毕。


6. 总结

  • 本文主要讲解了Android开发中主流的技术框架MVCMVP 与 MVVM模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试篇:SpringCloud

一、SpringCloud常见的组件有什么&#xff1f; 1、常见微服务功能架构图 2、阿里巴巴SpringCloud常用组件 注册中心/配置中心&#xff1a;Nacos负载均衡&#xff1a;Ribbon服务调用&#xff1a;Feign服务保护&#xff1a;Sentinel服务网关&#xff1a;Gateway 二、服务注册…

Compose Desktop 实战 宝可梦图鉴

Compose Desktop 实战 宝可梦图鉴 前言 阅读本文需要一定compose基础&#xff0c;如果没有请移步Jetpack Compose入门详解&#xff08;实时更新&#xff09; 接口数据来源于pokeapi 项目源代码 如果你觉得不错&#xff0c;请给我一个star&#xff0c;THKS 实现效果 闲话不…

php通过cURL爬取数据(3):CURLINFO_HTTP_CODE返回0的排查和解决方案

CURLINFO_HTTP_CODE返回0的排查和解决方案 一、curl本地服务器需要DNS解析域名二、如何排查错误原因三、无法解析 DNS的程序升级方案四、宝塔配置DNS的操作方法1.etc/resolv.conf2.通过GUI界面 一、curl本地服务器需要DNS解析域名 在使用 curl 命令发送请求到域名地址&#xf…

测试(二)

1.软件测试的生命周期 需求分析→测试计划→ 测试设计→ 测试开发→ 测试执行→ 测试评估 2.如何描述一个Bug 3.Bug的优先级 1、Blocker&#xff08;崩溃&#xff09;&#xff1a; 阻碍开发或测试工作的问题&#xff1b;造成系统崩溃、死机、死循环&#xff0c;导致数据库数…

Unity基础 视频组件VideoPlayer,视频的播放与控制

在Unity中&#xff0c;视频播放功能具有广泛的应用&#xff0c;以下是一些视频播放在Unity中的常见用途&#xff1a; 游戏引入和过场动画&#xff1a;使用视频播放可以在游戏开始或过场动画中添加引人注目的视频&#xff0c;为游戏制造氛围和引起玩家的兴趣。这种方式可以通过播…

CSS基础学习--11 padding(填充)

一、定义 CSS padding&#xff08;填充&#xff09;是一个简写属性&#xff0c;定义元素边框与元素内容之间的空间&#xff0c;即上下左右的内边距。 当元素的 padding&#xff08;填充&#xff09;内边距被清除时&#xff0c;所释放的区域将会受到元素背景颜色的填充。 单独使…

Linux运维监控学习笔记1

1. 监控系统的概念&#xff1a; 监控系统&#xff0c;将所有需要监控的服务器及其各种各种需要的状态数据都实时地收集&#xff0c;并图形化地展示&#xff0c;并可以进行报警&#xff0c;让机器主动及时地与人沟通。 2. 为什么要监控&#xff1f; 答&#xff1a;实时地收集数…

kubernetes(k8s)理论篇

注意&#xff1a;kubeadm与docker是有版本要求的。 如果版本不兼容&#xff0c;初始化 kubeadm是会出现以下问题。 学习k8s掌握知识 基础概念 什么是 Pod 控制器类型 K8S 网络通讯模式 Kubernetes 构建 K8S 集群 资源清单 资源 掌握资源清单的语法 编写 Pod 掌握 Pod 的…

JVM知识点整理

JVM 回收哪个区域&#xff1f;关联面试题&#xff1a;fullgc会回收方法区&#xff08;元空间&#xff09;吗? 怎么判断对象可以被回收了关联面试题&#xff1a;哪些对象可以作为 GC Root &#xff08;两栈两方法&#xff09; JVM GC什么时候执行&#xff1f;分代回收机制思考&…

docker容器启动的问题 - docker容器和虚拟机的比较 - docker的底层隔离机制

目录 一、docker容器启动的问题&#xff1f; 二、什么是docker仓库&#xff1f; 三、虚拟机和docker容器的区别&#xff1a; docker的优势&#xff1a; docker的缺点&#xff1a; 对比&#xff1a; 四、docker的底层隔离机制 参考文献&#xff1a;LXC linux容器简介——…

图像 检测 - CenterNet: Objects as Points (arXiv 2019)

CenterNet: Objects as Points - 目标作为点&#xff08;arXiv 2019&#xff09; 摘要1. 引言2. 相关工作3. 准备工作4. 目标作为点4.1 3D 检测4.2 人体姿态估计 5. 实施细节6. 实验6.1 目标检测6.1.1 附加实验 6.2 3D 检测6.3 姿态估计 7. 结论References附录A&#xff1a;模型…

【C数据结构】动态顺序表_SeqList

目录 【1】数据结构概述 【1.1】什么是数据结构&#xff1f; 【1.2】数据结构分类 【1.3】数据结构术语 【2】数据结构特点 【2】动态顺序表 【2.1】动态顺序表定义数据结构和接口 【2.1】动态顺序表创建初始化 【2.2】动态顺序表初始化 【2.3】动态顺序表内存释放 【…

mac电脑储存内存越来越小如何清理释放空间?

如果你是一位Mac系统的用户&#xff0c;可能会发现你的电脑储存空间越来越小。虽然Mac系统设计得非常优秀&#xff0c;但是系统数据和垃圾文件也会占据大量的储存空间。在这篇文章中&#xff0c;我们将探讨mac系统数据怎么这么大&#xff0c;以及mac清理系统数据怎么清理。 一…

万字详解常用设计模式

本文是博主在工作中对常用设计模式的使用经验总结归纳而来分享给大家。 设计模式一共有23种&#xff0c;本文讲解涉及如下&#xff1a; 责任链模式 模板方法模式 发布订阅模式 策略模式 三大分类 业界一般将设计模式分为三大类&#xff1a; 创建型模式&#xff1a;对类的实…

5、产品经理的工作职责OR主要工作技能和工具

1、产品经理的工作职责 我们通过一个案例来了解产品经理的工作职责。 老板让你给他点餐&#xff0c;你应该怎么做&#xff1f;你需要考虑哪一些方面的问题&#xff1f; 例如&#xff1a;你预算多少&#xff0c;预算是十块钱还是100块还是1000块。有没有忌口&#xff0c;口味…

Kafka详解(一)

第1章 Kafka概述 1.1 定义 1.2 消息队列 目前企业中比较常见的消息队列产品主要有Kafka、ActiveMQ、RabbitMQ、RocketMQ等。Message Queue ② 在大数据场景主要采用Kafka作为消息队列 ② 在JavaEE开发中主要采用ActiveMQ、RabbitMQ、RocketMQ Kafka存储数据&#xff0c;且保证…

「网络编程」第一讲:初识网络_网络基础1

「前言」文章是关于网络编程方面的&#xff0c;今天内容大致是网络基础&#xff0c;讲解下面开始&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 青山不改&#xff0c;绿水长流 ——白居易 目录 一、…

新手快速搭建springboot项目

一、创建项目 1.1、创建项目 1.2、配置编码 1.3、取消无用提示 1.4、取消无用参数提示 二、添加POM父依赖 <!-- 两种方式添加父依赖或者import方式 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-p…

微信小程序触底加载scroll-view

微信小程序触底加载 scroll-view 了解什么是触底加载&#xff1f; 需求&#xff1a;有个固定高度的容器&#xff0c;实现容器里面的内容触底加载 1、内容盒子的高度 2、盒子里内容的总高度 3、滚动条的scrollTop 触底加载的原理就是 当里面的容器触底的时候进行分页&#xff0…

Ansible-playbook-roles安装lnmp

使用roles安装lnmp 1、准备四台主机 192.168.142.10 192.168.142.20 192.168.142.30 192.168.142.40 2、10作为ansible管理端 首先ssh连接剩下三台主机 3、vim/etc/ansible/hosts 添加[nginxservers]配置nginx ip,[phpservers]php ip,[mysqlservers]mysql ip 4、cd /etc/ansibl…