一个简单的MVP模式案例
1. 问题背景
首先需要清楚的一点是MVP模式的设计初衷是:为了解决在MVC模式中,过于复杂的逻辑和界面之间的交互中Activity的职责不单一的问题,Activity既充当了View层,又充当了Controller层的角色。刨除问题的复杂度,直接谈MVP模式的优越性,都是耍流氓。
这也就是为什么我们很多人,为什么不愿意学习MVP的原因。但是如果遇到了一个比较复杂的问题,MVP的解耦能够让你更加轻松地应对需求的迭代。
本文将一个案例来解释MVP模式的设计方法,但是这里有一个矛盾点:MVP模式本身应该作用于较复杂问题的,但是本文作为入门文章又必须使用一个较简单的场景去设计,这样才能容易看出MVP的结构。
场景描述如下:
APP中有一本书(Model),书本的价格会显示在Activity(View)中,Activity中有两个按钮,可以对书本的价格进行控制(Presenter)。
2. MVP模式的实现
基于上面提出的场景,我们先简单的设计界面:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.orzangleli.mvpdemo.MainActivity"><TextViewandroid:id="@+id/desc"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Hello World!"android:textSize="16dp"android:gravity="center_vertical"android:padding="5dp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:id="@+id/increase"android:layout_width="0dp"android:layout_height="wrap_content"android:text="涨价1元"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@+id/decrease"app:layout_constraintTop_toBottomOf="@id/desc"android:layout_marginTop="60dp"/><Buttonandroid:id="@+id/decrease"android:layout_width="0dp"android:layout_height="wrap_content"android:text="降价1元"app:layout_constraintLeft_toRightOf="@id/increase"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="@id/increase"/></android.support.constraint.ConstraintLayout>
复制代码
我们设计书本的数据模型BookVo
。
public class BookVo {private String name;private int price;private String author;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("BookVo{");sb.append("name='").append(name).append('\'');sb.append(", price=").append(price);sb.append(", author='").append(author).append('\'');sb.append('}');return sb.toString();}
}
复制代码
Activity只负责显示书本的信息,不参与涨价/降价的逻辑处理,所以我们需要创建一个Presenter类,把价格逻辑交给他处理,处理完之后再在Activity中显示。
Presenter类应该具有涨价/降价的能力,因此我们把Presenter设计成接口更加合理。IPresenter.java
的内容如下:
public interface IPresenter {void increasePrice();void decreasePrice();
}
复制代码
再设计一个PresenterImpl
类继承IPresenter
接口,并实现涨价和降价的两个方法。因为需要在Presenter中操作Model,并在View中显示,所以Presenter
需要持有Model和View的对象。Model对象很简单,直接将BookVo
传给Presenter
即可,但是View对象如何处理呢?
我们制定一个IView
接口,向Presenter
暴露我们能够提供的能力,比如这个场景里的显示书籍信息,于是IView
接口内容如下:
public interface IView {void showBookInfo(BookVo vo);
}
复制代码
我们让MainActivity
实现IView
接口,
@Override
public void showBookInfo(BookVo vo) {this.mDescTv.setText(vo.toString());
}
复制代码
现在我们只需要给Presenter添加一个构造方法就行,构造方法中添加两个参数:BookVo和IView对象。PresenterImpl.java
代码如下:
public class PresenterImpl implements IPresenter {private IView mIView;private BookVo mBookVo;public PresenterImpl(IView iView, BookVo vo) {this.mIView = iView;this.mBookVo = vo;}@Overridepublic void increasePrice() {Log.i("lxc", " ---> 涨价了一元");mBookVo.setPrice(mBookVo.getPrice() + 1);this.mIView.showBookInfo(mBookVo);}@Overridepublic void decreasePrice() {Log.i("lxc", " ---> 降价了一元");mBookVo.setPrice(mBookVo.getPrice() - 1);this.mIView.showBookInfo(mBookVo);}
}
复制代码
MainActivity
代码如下:
public class MainActivity extends AppCompatActivity implements IView{private TextView mDescTv;private Button mIncreaseBtn, mDecreaseBtn;private IPresenter mPresenter;private BookVo vo;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();initPresenter();mDescTv = findViewById(R.id.desc);mIncreaseBtn = findViewById(R.id.increase);mDecreaseBtn = findViewById(R.id.decrease);mIncreaseBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.increasePrice();}});mDecreaseBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.decreasePrice();}});mDescTv.setText(vo.toString());}private void initData() {vo = new BookVo();vo.setName("《百年孤独》");vo.setAuthor("泰戈尔");vo.setPrice(100);}private void initPresenter() {mPresenter = new PresenterImpl(this, vo);}@Overridepublic void showBookInfo(BookVo vo) {this.mDescTv.setText(vo.toString());}
}
复制代码
现在就可以看到效果了。
3.若干思考
- MVP与MVC有什么区别?有本质区别么?
- 案例中P层和M层为什么要设计成接口?
4. 后续
本文中的Demo源码和思考答案将存在于我的微信公众号中,获取源码(Source)请回复"S2",获取答案(Answer)请回复"A2"。另外欢迎大家关注我的微信公众号~么么么
一个简单的MVP模式案例相关推荐
- 超简单的MVP模式案例
在说mvp之前,先说下mvc: MVC( Model View Controller):一种将逻辑和视图分隔开来的架构设计,起源于web端.其实 Android应用的开发中本身可视为一种MVC架构. ...
- 简单易懂 MVP 模式
Android MVP 模式 [1] 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. ...
- php 跳转qq群代码_一个简单QQ群聊案例代码解析(PHP实现)
问题: 使用面向对象编程的方式实现以下业务逻辑: 1. 张三使用账号a,密码b登录了qq 2. 显示出张三最后的登录的时间 3. 张三查看了 1小时内的行政部门群的信息(这个群里有张三,李四,王五,其 ...
- 一个简单的生产者消费者案例
生产者消费者模式 为什么要引入生产者消费者模式 简单来说就是为了解决多线程下程序先后执行问题 遇到的例:实际生产中出现的场景 服务D依赖于服务A.B.C产生的数据,服务D必须等待A.B.C产生结果并持 ...
- [go]---从java到go(02)---一个简单的handler模式的实现
类似于责任链模式吧,不同类实现相同的入参,执行不同的操作,一个执行完再确定要不要执行下一个. 用go实现: 1.定义一个接口 后面所有的handler都要实现这个接口的handler方法 type I ...
- C++ 有关string类的基本语法以及一个简单算法 理论加案例的形式
#include<iostream> using namespace std; #include"string" //string类的头文件 #include" ...
- Pygame飞机大战一个简单的双人模式测试
在之前完成了飞机大战整个项目以后就想提升一下,所以萌生出了做双人模式的想法. 那么在单人模式的基础上重写一个HeroB,我们将一号玩家称为HeroA class HeroB(Plane):" ...
- 从一个简单的AT模式事务例子入手
傅青阳眯了一下眼睛,心想这个手下飘了,不给点颜色看看是不行了:talk is cheap show me the code.从AT模式的源码来开始讲整个流程. 元始背转身,负手而立,白衣飘飘,一副胸有 ...
- 一个简单的MVC模式练习
控制层Action接受从模型层DAO传来的数据,显现在视图层上. package Action;import java.sql.Connection; import java.sql.SQLExcep ...
最新文章
- 软件工程导论结对项目
- python使用imbalanced-learn的OneSidedSelection方法进行下采样处理数据不平衡问题
- javascript,令人着迷了!
- 【Android Gradle 插件】ProductFlavor 配置 ( applicationId 配置 | SdkVersion 相关配置 | version 应用版本配置 )
- 主程序与子程序不在同一程序模块中_深度解析S7200系列PLC带参数子程序用法
- sonar 质量配置 操作(质量规则)
- c# combobox集合数据不显示_excel打开数据时显示乱码/问号amp;看起来一样却v不出来怎么办...
- 更新widget 导致widget host(home) 挂掉
- mosquitto源码分析(二)
- Leetcode每日一题:23.merge-k-sorted-lists(合并K个排序链表)
- 应聘c语言面试试题,c语言面试最必考的十道试题,求职必看!!!
- Hadoop-MapReduce
- 酒柜设计也可以很“特色”
- C语言(素数)[解法]:编写prime(m)判断m是否为素数,当m为素数返回1,否则返回0;
- 云服务器操作系统 版本选择,云服务器选择操作系统版本
- 使用Itext结合Jfreechart图表导出带图表的word文档
- Flex布局常见父项属性(一)- flex-direction
- moment 与 moment.unix 区别 moment用法
- 活死细胞染色——Cell Meter 细胞活性检测试剂盒
- 自动切换背景的登录页面
热门文章
- boost::graph模块使用write_graphviz 输出 BGL adjacency_list 的简单示例
- boost::array用法的测试程序
- boost::fusion::as_list用法的测试程序
- boost::function_types::components用法的测试程序
- ITK:在矢量图像上执行注册
- VTK:可视化之Hanoi
- VTK:模型之Delaunay3D
- VTK:图片之FillWindow
- C语言判断一个数是否是回文数Palindrome算法(附完整源码)
- c++对象拷贝语意学