MVP设计模式
传统的MVC(Model、View、Controller)模式,作为View层的Activity或者Fragment,通常背负的任务都非常繁重,不仅要处理View的更新,还要处理耗时的计算等操作,大大降低了代码的可阅读性,甚至有时候改代码会造成一发动全身,各种修修补补,最终导致项目臃肿难以抽离。MVP(Model、View、Presenter)模式能让代码阅读起来更加清晰,我们作为一名程序员,很有必要提升自己的代码编写质量,不仅仅给自己阅读,也要给身边的同事朋友们阅读。
MVC模式中View层不仅要对数据model处理,还要肩负View的更新,造成代码臃肿,耦合严重。
MVP模式中将View与model分离,不直接操作数据Model,让Presenter去做相应的计算、耗时操作等,而View就只做些单一的刷新View的操作,大大降低代码的耦合度,MVP模式适合于中小型项目,如果是大型的项目,可考虑用MVVM设计模式。
好了,废话不多说,多写代码才能悟道其中代码的真理,我就用最简单的例子来开展MVP模式的使用。
第一步
我们先准备两个基础的接口:
IBaseVIew.java
/**
* @author : zzj
* @date : 2019/1/31
* @desp : mvp模式中的V层
*/
public interface IBaseView<T> {
}
IBasePresenter.java
/**
* @author : zzj
* @date : 2019/1/31
* @desp : mvp设计模式中的P层
*/
public interface IBasePresenter<T> {
/**
* 关联activity或fragment
* @param mvpView
*/
void attachView(T mvpView);
/**
* activity或fragment在destroyed时与View分离
* 避免耗时操作更新View
*/
void detachView();
}
第二步
正式使用,建立契约类,我就以排序为例子吧,建一个TestContract.java
TestContract.java
/**
* @author : zzj
* @date : 2019/1/31
* @desp : 按谷歌官方推荐指定一个契约类
*/
public interface TestContract {
interface Presenter extends IBasePresenter<MvpView>{
void init(int[] array);
void sort(int[] array, int sort);
}
interface MvpView extends IBaseView<Presenter>{
void sortBefore(String s);
void sortAfter(String s);
void showToast(String msg);
}
}
其中MvpView接口需要我们的Activity或者Fragment去实现,我们在实际开发中可自己编写MvpView的相应方法来处理我们的项目,记得就是MvpView在实现的时间我们尽量保持做View的更新,避免逻辑处理;而Presenter接口由具体的Presenter类来实现,实现具体的逻辑,如:
TestPresenter.java
/**
* @author : zzj
* @date : 2019/1/31
* @desp : 测试
*/
public class TestPresenter implements TestContract.Presenter {
public static final int SORT_SELECT = 0x01;
public static final int SORT_INSERT = 0x02;
private TestContract.MvpView mMvpView;
@Override
public void init(int[] array) {
StringBuilder stringBuilder = new StringBuilder();
for (int item : array) {
stringBuilder.append(" " + item);
}
if (mMvpView != null) {
mMvpView.sortBefore("排序前:" + stringBuilder.toString());
}
}
@Override
public void sort(int[] array, int sort) {
switch (sort) {
case SORT_SELECT:
array = selectSort(array);
break;
case SORT_INSERT:
array = insertSort(array);
break;
}
StringBuilder stringBuilder = new StringBuilder();
for (int item : array) {
stringBuilder.append(" " + item);
}
if (mMvpView != null) {
mMvpView.showToast(sort == SORT_SELECT ? "选择排序" : "插入排序");
mMvpView.sortAfter("排序后:" + stringBuilder.toString());
}
}
/**
* 选择排序
*/
public int[] selectSort(int[] array) {
for (int i = 0; i < array.length; i++) {
int minPos = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < array[minPos]) {
minPos = j;
}
}
if (array[i] > array[minPos]) {
int temp = array[i];
array[i] = array[minPos];
array[minPos] = temp;
}
}
return array;
}
/**
* 插入排序
*/
public int[] insertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int temp = array[i];
for (int j = i - 1; j >= 0; j--) {
if (array[j] > temp) {
array[j + 1] = array[j];
array[j] = temp;
}
}
}
return array;
}
@Override
public void attachView(TestContract.MvpView mvpView) {
this.mMvpView = mvpView;
}
@Override
public void detachView() {
mMvpView = null;
}
特别提醒
在实现Presenter时记得处理attachView()和detachView()方法,避免View不刷新。
最后一步
最后一步当然是我们的Activity实现
MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements TestContract.MvpView {
private TestContract.Presenter testPresenter;
private int[] array = new int[]{6, 5, 9, 1};
private TextView tvBefore,tvAfter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testPresenter = new TestPresenter();
testPresenter.attachView(this);
tvBefore = findViewById(R.id.tv_array);
tvAfter = findViewById(R.id.tv_sort_array);
testPresenter.init(array);
findViewById(R.id.btn_one).setOnClickListener(onClickListener);
findViewById(R.id.btn_two).setOnClickListener(onClickListener);
}
private View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_one:
testPresenter.sort(array.clone(), TestPresenter.SORT_SELECT);
break;
case R.id.btn_two:
testPresenter.sort(array.clone(), TestPresenter.SORT_INSERT);
break;
}
}
};
@Override
public void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
@Override
public void sortBefore(String s) {
tvBefore.setText(s);
}
@Override
public void sortAfter(String s) {
tvAfter.setText(s);
}
@Override
protected void onDestroy() {
super.onDestroy();
//在销毁的时候分离
testPresenter.detachView();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns: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=".MainActivity">
<TextView
android:id="@+id/tv_array"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="16sp"
android:text="排序前:"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toTopOf="@+id/tv_sort_array"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/tv_sort_array"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="排序后:"
android:textColor="@android:color/black"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/btn_one"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/btn_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择排序"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="150dp"
android:text="插入排序"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
附带项目传送地址
https://github.com/zhouzhijiang/MvpPrototype
结语
简单的介绍和演示了MVP模式的作用以及效果,在日常开发中能有效帮助我们提高自身的coding能力。欢迎大家拍砖点赞分析收藏,谢谢大家。