MVP这种设计模式在Android领域越来越火,经常会听到某某Android应用采用了MVP+Retrofit+RxJava的架构,甚至很多工程师都说面试过的人喜欢提MVP,却并不知道它真正的机制。那么,究竟什么是MVP模式,它又与MVC模式有什么异同呢?
相信对于大部分开发者而言,MVC是一种非常熟悉的模式,它广泛的应用于web等诸多常见的软件中。MVC将整个工程分为三个部分,Model(模型)、View(视图)、Controller(控制器)中,对于以往常用的Android项目而言,更多的人们会将布局文件作为View,而将Activity(或Fragment,下同)作为Controller。
然而,在Activity中实际上做了很多的事情,不仅处理了业务逻辑,有时也会对UI进行操作,这样就使得Activity看起来既像Controller层又像View层,随着项目的不断发展,这些Activity和Fragment就会变得越来越臃肿,难以扩展和维护,因此便出现了MVP模式。
作为MVC的演化版本,在MVP模式中,将整个工程分为了Model(模型)、View(视图)、Presenter(表示器),与MVC的异同见下图(来自图片):
在图中我们能够看出,MVP与MVC最大的不同就是在于Model与View并不能直接交互,而是隔着一层Presenter,相比于MVC,MVP中的Model会更少的关注业务逻辑,与View的耦合度也进一步降低,这种模式不仅使得代码逻辑更加清晰,同时也能减少我们部署以及单元测试的时间。
网上很多例子都是使用的用户登录(当然也有很多比较复杂的),所以实现了一个其他的功能,主要用于说明各模块之间的关系。
demo实现的效果如下图,主要功能为输入一个字符串,点击按钮将它变成大写并且输出
在这个demo中的java代码结构如下图:
(1)Model层
在Model层中,我们定义了一个Model,名为MyModel
package com.example.steveyg.androiddemo.model;
/**
* Created by steveyg on 2016/12/20.
*/
public class MyModel {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
一般很少有实体只包含一个属性,不过此处用于举例就写了一个简单的实体类。接着定义了相应的biz
package com.example.steveyg.androiddemo.biz;
/**
* Created by steveyg on 2016/12/20.
*/
public interface IMyBiz {
public void exec(String str, OnExecListener listener);
}
package com.example.steveyg.androiddemo.biz;
import com.example.steveyg.androiddemo.model.MyModel;
/**
* Created by steveyg on 2016/12/20.
*/
public interface OnExecListener {
void execSuccess(MyModel model);
}
package com.example.steveyg.androiddemo.biz;
import com.example.steveyg.androiddemo.model.MyModel;
/**
* Created by steveyg on 2016/12/20.
*/
public class MyBiz implements IMyBiz {
@Override
public void exec(final String str, final OnExecListener listener) {
new Thread() {
@Override
public void run() {
super.run();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
MyModel model = new MyModel();
String result = str.toUpperCase();
model.setStr(result);
listener.execSuccess(model);
}
}.run();
}
}
在实现IMyBiz接口的时候,采用了异步的操作,因为大部分需要处理数据的时候都是要和数据库或服务器交互的。
(2)View层
在View层中,首先定义了一个布局文件,里面有一个提示语,一个输入框和一个按钮:
接着,我们定义一个接口IMyView,里面定义了视图层需要进行的操作:
package com.example.steveyg.androiddemo.view;
import com.example.steveyg.androiddemo.model.MyModel;
/**
* Created by steveyg on 2016/12/20.
*/
public interface IMyView {
public String getStr();
public void showSuccess(MyModel model);
}
getStr()用来获取输入框中的文字,showSuccess()用于展示最后的结果。接着,在Activity中实现相应的方法
package com.example.steveyg.androiddemo.activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.steveyg.androiddemo.R;
import com.example.steveyg.androiddemo.model.MyModel;
import com.example.steveyg.androiddemo.presenter.MyPresenter;
import com.example.steveyg.androiddemo.view.IMyView;
public class MainActivity extends AppCompatActivity implements IMyView {
private EditText mEditText;
private Button mButton;
private MyPresenter mPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
@Override
public String getStr() {
return mEditText.getText().toString();
}
@Override
public void showSuccess(MyModel model) {
Toast.makeText(this,model.getStr(),Toast.LENGTH_SHORT).show();
}
private void init(){
mPresenter = new MyPresenter(this);
mEditText = (EditText)findViewById(R.id.edit);
mButton = (Button)findViewById(R.id.submit);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.exec();
}
});
}
}
(3)Presenter层
package com.example.steveyg.androiddemo.presenter;
import android.os.Handler;
import com.example.steveyg.androiddemo.biz.IMyBiz;
import com.example.steveyg.androiddemo.biz.MyBiz;
import com.example.steveyg.androiddemo.biz.OnExecListener;
import com.example.steveyg.androiddemo.model.MyModel;
import com.example.steveyg.androiddemo.view.IMyView;
/**
* Created by steveyg on 2016/12/20.
*/
public class MyPresenter {
private IMyBiz myBiz;
private IMyView myView;
private Handler mHandler = new Handler();
public MyPresenter( IMyView view) {
this.myBiz = new MyBiz();
this.myView = view;
}
public void exec() {
myBiz.exec(myView.getStr(), new OnExecListener() {
@Override
public void execSuccess(final MyModel model) {
//通过Handler在UI线程中处理
mHandler.post(new Runnable() {
@Override
public void run() {
myView.showSuccess(model);
}
});
}
});
}
}
至此,一个简单的MVP demo就完成啦,不难看出,相比于MVC模式,代码量增加了很多,但是逻辑更加清晰,在实际的项目中,还是要好好设计下整个项目的结构,而且选定一种模式最好能够坚持的使用下去,在中途切换模式,有可能会导致整个项目的重构。
参考资料
http://blog.csdn.net/lmj623565791/article/details/46596109
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0227/2503.html
http://www.cnblogs.com/liuling/archive/2015/12/23/mvp-pattern-android.html