从最简单的HelloWorld理解MVP模式
大多数编程语言相关的学习书籍,都会以hello,world这个典型的程序作为第一个示例。作为Android应用开发者,无论使用eclipse还是用android studio,在新建项目的时候,一直按IDE默认选择项,下一步进行下去,就会创建出一个可以运行的hello,world应用程序。对于这个程序,可以认为是采用MVC模式,对应关系为:
- View:对应于布局文件
- Model:业务逻辑和实体模型
- Controller:对应于Activity
但是数据绑定、事件处理(hello world程序没有)的代码都在Activity中,Activity看起来既担任了View的角色,又担任了Controller的角色。这样随着程序业务逻辑越来越复杂,Activity中的代码就会越来越多,最终结果就是程序的耦合度越来越高,程序修改和维护越来越难。于是MVP模式的优点就显示出来了。下面我就以这个最简单的程序,来谈谈我对mvp模式的理解。
先上代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.joy.etest.MainActivity"> <TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" /> <Button
android:id="@+id/btn_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="测试"/> </LinearLayout>
布局文件很简单,一个 TextView ,程序运行显示 “Hello World!”。这里我增加了一个Button,点击Button,开始倒计时10秒钟,以此来模拟一些耗时的操作,10秒钟后,TextView显示"Hello MVP!"。再看java代码,在MVC模式下,我们直接在 Activity 中通过 setText 方法,就可以给 TextView 设置显示的内容。MVP模式相对于MVC模式来说,就是将Controller这部分从Activity中分离出来,让Activity只担任View的角色,View和Model之间的桥梁作用由 presenter 来承担,从而达到解耦的目的。具体的方法就是通过接口回调来实现。下面是时候展现真正的步骤了:
首先定义一个接口,就叫 IShowView吧,里面有一个 show 方法,用于给TextView设置显示内容
package com.example.joy.mvptest;
public interface IShowView {
void show(String str);
}
MainActivity实现上述接口:
package com.example.joy.mvptest; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends AppCompatActivity implements IShowView, View.OnClickListener { private TextView mTvShow;
private Button mBtnTest; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvShow = (TextView) findViewById(R.id.tv_show);
mBtnTest = (Button) findViewById(R.id.btn_test);
mBtnTest.setOnClickListener(this); } @Override
public void show(String str) {
mTvShow.setText(str);
} @Override
public void onClick(View v) {
if(v.getId() == R.id.btn_test) { }
}
}
代码很简单。MainActivity实现接口中的show方法,即为TextView赋值。Button的点击事件暂时没有写。
其次,presenter模块也要定义一个接口,与 MainActivity 实现的接口提供类似的方法,就叫 IPresenter 吧:
package com.example.joy.mvptest.presenter;
public interface IPresenter {
void show();
}
注意,这个接口里的 show 方法没有参数,和前面 IShowView 中的方法签名不一样,当然,你也可以不命名为 show ,方法名可以自己随便起。这里的方法参数完全是根据实际需要来确定。有了接口,当然还需要有接口的实现类,命名为 PresenterComl :
package com.example.joy.mvptest.presenter; import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log; import com.example.joy.mvptest.IShowView; public class PresenterComl implements IPresenter {
private IShowView iShowView; public PresenterComl(IShowView iShowView) {
this.iShowView = iShowView;
} @Override
public void show() {
new AsyncTask<Void, Void, Void>() { @Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d("joy99", "下载完成。");
iShowView.show("Hello,MVP!");
} @Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 10; i++) {
Log.d("joy99", "正在下载...预计剩余时间 " + (10 - i) + "秒");
SystemClock.sleep(1000);
}
return null;
}
}.execute(); }
}
此处我用了一个异步任务。将倒计时打印出来,模拟一些耗时的数据操作,比如网络请求等等。该类中声明了一个IShowView接口的实现类的对象,iShowView,倒计时完成,调用iShowView的show方法,将“结果”传递过去,典型的接口回调的用法。
剩下的最后一步就很清晰了,在 MainActivity 中定义 PresenterComl 类的对象 iPresenter,然后,在Button的点击事件中,调用 iPresenter 的show方法。注意构造方法中MainActivity本身,作为实现 IShowView 的类的对象传递进去。修改后的 MainActivity 类代码如下:
package com.example.joy.mvptest; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; import com.example.joy.mvptest.presenter.IPresenter;
import com.example.joy.mvptest.presenter.PresenterComl; public class MainActivity extends AppCompatActivity implements IShowView, View.OnClickListener { private TextView mTvShow;
private Button mBtnTest; private IPresenter iPresenter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvShow = (TextView) findViewById(R.id.tv_show);
mBtnTest = (Button) findViewById(R.id.btn_test);
mBtnTest.setOnClickListener(this); iPresenter = new PresenterComl(this);
} @Override
public void show(String str) {
mTvShow.setText(str);
} @Override
public void onClick(View v) {
if(v.getId() == R.id.btn_test) {
iPresenter.show();
}
}
}
上面黄色底纹的代码就是这最后一步,将Presenter部分与Activity建立关联。
OK,通过这样一个小程序将MVP模式分析了一下,它的本质其实就是接口回调。当然,对于这样一个小的不能再小的程序来说,用MVP模式,确实看起来更复杂了。但是代码逻辑复杂了,MVP模式的优势就显示出来了。最后总结一下:
使用MVP模式会使得代码多出一些接口,但是使得代码逻辑更加清晰,尤其是在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一个Presenter,这样代码既清晰、逻辑明确又方便我们扩展。当然如果我们的业务逻辑本身就比较简单的话使用MVP模式就显得没那么必要。所以我们不需要为了用它而用它,具体的还是要要业务需要。
从最简单的HelloWorld理解MVP模式的更多相关文章
- 用最简单的例子理解备忘录模式(Memento Pattern)
简单来说,备忘录模式就是支持回退操作.假设让一个Notepad支持回退操作,如何实现呢? 首先需要一个备忘录类. public class Memento { private string _msg; ...
- 用最简单的例子理解复合模式(Composite Pattern)
在显示树形结构时,复合模式有很好的体现.本篇显示如下部门结构: 以上,有的节点包含子节点,有的节点部包含子节点.不管是什么节点,每个节点就代表一个部门. 首先设计一个关于部门的抽象基类. public ...
- 用最简单的例子理解命令模式(Command Pattern)
假设想让遥控器控制电灯的开关.电视机的开关和切换,该如何做? 所有的开.关.切换都是遥控器发出的指令,把这些指令统一抽象成一个接口. public interface IControl { void ...
- 用最简单的例子理解迭代器模式(Iterator Pattern)
迭代器模式的需求来自:需要对一些集合进行迭代,而迭代的方式可能有很多种. 说到迭代,动作大致包括设置第一个位置,获取下一个位置元素,判断是否迭代结束,获取当前位置元素,大致就这么些.把这些迭代动作封装 ...
- 用最简单的例子理解模板方法模式(Template Method Pattern)
假设要做一道红烧肉,做法有很多,在不同的做法中都有相同的部分,比如都要放油.放肉.放调料等.也有不同之处,比如有些做法放可乐,有些做法放甜蜜酱,等等. 先提炼出一个抽象类,该类不仅有制作红烧肉的各个步 ...
- Thinking In Design Pattern——MVP模式演绎
原文<Thinking In Design Pattern——MVP模式演绎>不知为何丢失了,故重新整理了一遍. 目录 What Is MVP Domain Model StubRepos ...
- android MVP模式简单介绍
原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...
- Android MVP模式简单介绍:以一个登陆流程为例
老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚.简洁,流程更加清晰,对于后续版本迭代维护都挺方便.对于一些想要学习MVP模式的同学来讲,百度搜出来 ...
- c#中winform的MVP模式的简单实现
MVP模式是类似于MVC模式的一种设计模式,最近在做项目学习过程中遇到,弄了很久终于有一些眉目,这是学习过程中的一些笔记.MVP指的是实体对象Model.视图Viw和业务处理Presenter.MVP ...
随机推荐
- ganglia的yum插件的配置
由于默认的centos的库是不存在ganglia的相关软件,因此要重新配置yum的库 配置yum库 安装yum优先级插件 yum install yum-priorities 安装Epel 此处是6 ...
- HTML页面导出为Word
protected void btnExport_Click(object sender, EventArgs e) { string strFileName = DateTime.Now.ToStr ...
- 转载RabbitMQ入门(4)--路由
路由 (使用Java客户端) 在先前的指南中,我们建立了一个简单的日志系统.我们可以将我们的日志信息广播到多个接收者. 在这部分的指南中,我们将要往其中添加一个功能-让仅仅订阅一个消息的子集成为可能. ...
- 【JS】js获得下拉列表选中项的值和id
function tijiao(){ var elem = document.getElementById("dish_sort"); var index=elem.selecte ...
- 查询MySQL锁等待的语句
select 'Blocker' role, p.id, p.user, left(p.host, locate(':', p.host) - 1) host, tx.trx_ ...
- 精妙SQL语句 基础
精妙SQL语句SQL语句先前写的时候,很容易把一些特殊的用法忘记,我特此整理了一下SQL语句操作,方便自己写SQL时方便一点,想贴上来,一起看看,同时希望大家能共同多多提意见,也给我留一些更好的佳句, ...
- CSAPP(2):程序的汇编表示(Linux版)
程序员学习汇编代码的需求随着时间的推移发生了变化,开始时只要求程序员能直接用汇编语言编写程序,现在则要求他们能够阅读和理解编译器产生的代码. 下面是针对32位机器 数据格式 Intel用术语“字”(w ...
- bzoj 2502 清理雪道(有源汇的上下界最小流)
[题意] 有一个DAG,要求每条边必须经过一次,求最少经过次数. [思路] 有上下界的最小流. 边的下界为1,上界为无穷.构造可行流模型,先不加ts边跑一遍最大流,然后加上t->s的inf边跑 ...
- Tkinter教程之Toplevel篇
本文转载自:http://blog.csdn.net/jcodeer/article/details/1811341 '''Tkinter教程之Toplevel篇'''#TopLevel与Frame类 ...
- [HIve - LanguageManual] Subqueries
Subqueries in the FROM Clause Subqueries in the WHERE Clause Subqueries in the FROM Clause SELECT .. ...