MVP模式分析及简单例子

来源:互联网 发布:克莱斯勒网络培训学院 编辑:程序博客网 时间:2024/05/06 02:28

一直在用MVC,感觉MVC才是最简单最好用的模式。也一直好奇MVP模式有什么神奇的地方,因为没用过MVP。
最近看了 一个项目中的代码,就是典型的MVP模式,当然有些地方用的还是mvc,比如登录界面,因为逻辑简单,就直接mvc写的。但是一些复杂的页面,功能多,且需要后期维护和业务修改的界面就用的MVP。这里也说些MVP的优势:
1、代码解耦
2、结构清晰
3、可复用、扩展性好
4、方便进行单元测试

再说下mvp的分层思想和每层代表的含义:
主要思想就是将数据层与视图层分开,彻底的分开,即m和v不直接打交道,而是通过一个中介p去联系。相比较mvc的话,mvc的m和v联系的还是比较密的。

MVP
M:就是数据层,主要负责数据的拉取和上传,就是网络请求吧。
V:就是view层,主要负责界面的ui展示
P:就是persenter,主要功能就是将m层请求的数据注入到v层,或者将v层提交的数据传递给m层并回调结果然后控制v层;

p层举个例子:
请求数据:m层主要写网络请求的代码,并通过接口回调结果。p层拿到m层的实例对象调用起请求代码的方法,并实现这个回调接口,这样就拿到数据了,拿到数据后通过v层的实例对象调用v层定义的ui方法,将数据传入,进而实现数据展示。
提交数据:同样也是m层写提交数据的网络代码,比如定义一个方法,传入要提交的参数进行网络操作,并将结果回调给接口。然后p层调用这个方法并实现该接口,那么就拿到这个结果了,拿到这个结果以后调用v的方法,进行其他操作。

而且一般我们都会写一个基类activity,并让这个基类activity为抽象activity,为什么要定义成抽象activity呢?主要是为了定义一个返回p层对象的抽象方法让子类去实现,这样就可以实例化不同需求场景下的不同逻辑控制层p,所以基类activity一般也会添加泛型p,并定义一个T presenter;那么子类activity可以直接用这个presenter调用对应的p层定义的方法。

写个例子:
1、登陆界面
首先我们看M层的代码:
LoginModel.java

public class LoginModel implements ILoginModel{@Overridepublic void login(String name,String pwd,ValueCallback<String> callback) {        //登陆操作        //根据用户输入的name和pwd调用登陆接口        //并根据登陆接口返回的结果情况调用        //callback.success(String s);或者callback.onfail(String code)    }  }

M层接口ILoginModel.java

public interface ILoginModel {    void login(String name,String pwd,ValueCallback<String> s);}

ValueCallback.java接口,用户将请求到的结果返回

public interface ValueCallback<T> {    void success(T s);    void onfail(String code);}

LoginModel类就是我们的M层的业务类,它实现了ILoginModel 接口,并实现login方法,里面需要传递用户输入的name和pwd。

再来看V层的代码,前面说过V层主要负责activity中的于view相关的操作。
那么登陆界面我们想一想需要的操作就是用户点击登陆按钮,然后我们将账号和密码拿到然后去调登陆接口是吧。ok,那么我们就定义一个用户点击登陆按钮的方法,和一个登陆请求成功了去首页的方法:

ILoginView.java接口

public interface ILoginView {    void login(String name,String pwd);    void startactivity();}

V层是给activity去实现的。那么接下来我们看P层怎么去写。

P层:
一般我们都会定义一个Presenter基类,里面写网络请求的方法。因为大多数页面都需要去后台拉数据吧。
那么我们就定义一个BasePresenter吧
BasePresenter.java

public abstract class BasePresenter<T extends BaseActivity> {    //网络请求     public abstract void initData();}

为什么要加一个baseactivity的泛型呢?是为了指定这个P是对应于哪一个页面,也为了方便之后的维护和检查,一目了然。
BaseActivity.java

public abstract class BaseActivity<T extends BasePresenter> extends Activity {    protected T basepresenter;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(getLayout());        basepresenter = initPresenter();        initView();    }    public abstract void initView();    public abstract  int getLayout();    public abstract T initPresenter();

可以看到baseactivity定义为抽象类,并添加了泛型,为什么要用泛型呢?我讲不出来,为了复用?我的解释是因为我们需要初始化Presenter对象,并且我们需要这个presenter对象为对应的P层的对象。
并添加了3个抽象方法
initview:子类去做一些控件初始化的操作
getLayout:子类需要设置layout布局id
initPresenter:子类返回的对应页面的p层对象

在看对应的逻辑控制层p代码:
LoginPresenter.java

public class LoginPresenter extends BasePresenter<LoginActivity> {    private LoginModel loginModel;    private ILoginView loginView;    public LoginPresenter(ILoginView loginView) {        this.loginView = loginView;        this.loginModel = new LoginModel();    }    @Override    public void initData() {    }    public void loginRequest(String name,String pwd){        loginModel.login(name,pwd,new ValueCallback<String>() {            @Override            public void success(String list) {                loginView.startactivity();            }            @Override            public void onfail(String code) {            }        });    }}

拿到m和v层的对象,我们看构造方法,m层是直接new的,但是v层是作为参数传递过来的,这也可以反过来解释为什么v层是让activity去实现。initdata不管,这个是通用的请求网络的操作。我们看loginRequest方法,这个方法是我们添加的,供loginactivity中用户点击登陆按钮后调用。是否登陆成功就在success或者onfail方法中了,如果登陆成功了,我们可以继续调用v层的startactivity方法去首页。

然后我们在看子类activity
LoginActivity.java

public class LoginActivity extends BaseActivity<LoginPresenter> implements ILoginView{    @Override    public void initView() {    }    @Override    public int getLayout() {        return 0;    }    @Override    public LoginPresenter initPresenter() {        return new LoginPresenter(this);    }    @Override    public void login(String name,String pwd) {         basepresenter.loginRequest(name,pwd);    }     @Override    public void startactivity() {           //intent打开activity    }}

这样一个mvp模式的登陆界面的逻辑就完成了。
我们说过mvp模式扩展性好,比如有新需求了,比如添加了注册和忘记密码功能,那么我们只需要在v层添加注册和忘记密码的方法,然后在m层添加对应的网络请求操作,然后在p层添加逻辑控制供activity调用就可以了。

这一套写下来对自己又巩固了一遍,确实感觉mvp模式扩展性很好,复用性高,而且代码解耦做的很好,很清晰,反观自己之前写的代码,真是乱七八糟。但是mvp模式的缺点也体现出来了,就是类多。所以如果逻辑简单的话还是不推荐用mvp,浪费时间不是。

原创粉丝点击