Android--MVP模式学习

MVP能够有效地降低View的复杂性,避免业务逻辑被塞进View中,使得View变得很混乱。MVP模式会解除View与Model的耦合,同时又带来了良好的可扩展型,可测试性,保证了系统的整洁性,灵活性。

MVP结构图:


MVP模式可以分离显示层和逻辑层,它们之间通过接口进行通信,降低耦合。理想化的MVP模式可以实现同一份逻辑代码搭配不同的显示界面,因为它们之间并不依赖于具体,而是依赖于抽象。这使得Presenter可以运用于任何实现了View逻辑接口的UI。

MVP并不是一个标准化的模式,它可以有很多种实现方式,我们也可以根据自己的需求和自己认为对的方式去修正MVP的实现方式,它可以随着Presenter的复杂程度变化。只要保证我们是通过Presenter将View和Model解耦合,降低类型复杂度,各个模块可以独立测试,独立变化,这就是正确的方向。


MVP模式的三个角色:

1. Presenter:交互中间人

Presenter主要作为沟通View和Model的桥梁,它从Model层检索数据后,返回给View层。使得View和Model之间没有耦合,也将业务逻辑从View角色上抽离出来

2. View:用户界面

View通常是指Activity,Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作通过会转交给Presenter进行实现,最后,Presenter调用View逻辑接口将结果返回给View元素。

3.Model:数据的存取

对于一个结构化的App来说,Model角色主要是提供数据的存取功能。Presenter需要通过Model层存储,获取获取数据,Model就像一个数据仓库。更直白地说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据获取方式的集合。我对于Model层的理解,一方面是数据的存取,另一方面不单单是表面意义上的存取,它可能只是实例化一个对象,用这个对象来存数据,也就是上面说的网路获取数据的角色。

实例:

从服务器下拉最新的几篇文章,显示在列表上

业务逻辑:

1.向服务器请求数据,并且将数据存储到数据库中

2.从数据库中加载文章列表

先从Presenter来看:哟用户需要从网络获取数据,因此需要一个数据获取的接口,也可以从本地数据库获取缓存的数据,因此需要一个从数据库加载缓存的接口。

package com.example.asus1.testmvp.Presenters;

import com.example.asus1.testmvp.Models.Articel;
import com.example.asus1.testmvp.Models.ArticelModel;
import com.example.asus1.testmvp.Models.ArticelModelImpl;
import com.example.asus1.testmvp.Views.ArticleViewInterface;

import java.util.List;

/**
 * Created by asus1 on 2018/3/7.
 */

public class ArticlePresenter {

    //ArticleView接口,代表了View接口角色
    ArticleViewInterface mArticleView;

    //文章数据的Model,也就是Model角色
    ArticelModel mArticleModel = new ArticelModelImpl();

    //从网络上获取文章的API
    ArticleAPI mArticelAPI = new ArticleAPIImpl();


    public ArticlePresenter(ArticleViewInterface viewInterface){
        mArticleView = viewInterface;
    }

    //获取文章,也就是我们的业务逻辑
    public void fetchArticels(){
        mArticleView.showLoading();

        mArticelAPI.fetchAeticel(new DataListener<List<Articel>>() {
            @Override
            public void onComplete(List<Articel> result) {
                mArticleView.showArticel(result);
                mArticleView.hideLoading();

                //储存到数据库
                mArticleModel.saveArticels(result);
            }
        });

    }

    public void loadArticelFromDB(){
        mArticleModel.loadArticelsFromCache(new DataListener<List<Articel>>() {
            @Override
            public void onComplete(List<Articel> result) {
                mArticleView.showArticel(result);
            }
        });
    }

}

在ArticelPresenter中持有了View和Model的引用,还有一个操作网络请求的ArticelAPIImpl对象。ArticelViewInterface就是主界面的逻辑接口,代表了View接口角色,用于Presenter回调View的操作。

public interface ArticleViewInterface<T> {

     void showLoading();
     void hideLoading();
    void showArticel(List<T> results);
}

ArticelModelImpl是对数据库的存取操作,用于保存网络上加载的数据,以及从数据库中加载文章缓存

public class ArticelModelImpl<T> implements ArticelModel<T> {

    List<T> mCacheArticels = new LinkedList<>();

    @Override
    public void saveArticels(List<T> results) {
        mCacheArticels.addAll(results);
    }

    @Override
    public void loadArticelsFromCache(DataListener<List<T>> listener) {
        listener.onComplete(mCacheArticels);
    }
}

ArticelActivity需要实现ArticelViewInterface接口,并且需要建立与Presenter的联系,ArticelActivity的业务逻辑都将交给Presenter进行处理,处理结果通过ArticelViewInterface接口回调给ArticelActivity。

public class ArticelsActivity extends AppCompatActivity implements ArticleViewInterface<Articel>{

    private ListView mListView;
    private ProgressBar mProgressBar;
    private List<Articel> mArticels = new LinkedList<>();
    private ArrayAdapter mAdapter;
    private ArticlePresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        
        //构建ArticelPresenter,与ArticelActivity建立关联
        mPresenter = new ArticlePresenter(this);
        //获取文章数据
        mPresenter.fetchArticels();
    }

    private void initViews(){
        mListView = (ListView)findViewById(R.id.articels_list_view);
        mAdapter = new ArticelAdapter(this,R.layout.view_list_item,mArticels);
        mListView.setAdapter(mAdapter);
        //进度条
        mProgressBar = (ProgressBar)findViewById(R.id.loading_progressbar);

    }

    @Override
    public void showArticel(List<Articel> results) {
        mArticels.clear();
        mArticels.addAll(results);
        mAdapter.notifyDataSetChanged();
    }
......

通过这个例子,可以看到Presenter对于View是完全解耦的,presenter依赖的是ArticelViewInterface抽象,而不是ArticelActivity,当UI界面发生变化的时候,只需要新的UI实现了ArticelViewInterfaceUI及相关的逻辑即可与Presenter迅速地协作起来,成本非常低。ArticesActivity此时的作用只是做一些View的初始化工作,职责单一,功能简单,易于维护。

在MVP中,View和Model不能直接通信,它们的交互都是通过Presenter。上面代码中,Presenter中还持有一个ArticelModel对象,这个ArticelModel就是Model角色,它负责处理数据。ArticelNModel同样也是一个接口,因此Presenter与Model也依赖于抽象而不是具体,使得ArticelModel的具体实现可以被轻易地替换。

这个例子中,presenter没有进行接口抽象,而是使用了具体类,因为业务逻辑相对稳定,所以使用具体类即可。如果业务逻辑相对来说易于变化,使用Presenter接口来进行抽象是最好不过的。

由此可见,Model——View——Presenter三者之间的关系都是松耦合的,Presenter持有View,Model引用都是抽象的,这样当UI发生变化的时候,只需要替换View即可。当数据库需要替换的时候,值需要重新构建一个实现AtricelModel接口的类并且实现想管 的存取逻辑即可。这样使得View,Model,Presenter三者之间可以独立的变化,测试也非常方便,可扩展性,灵活性都很高。   






猜你喜欢

转载自blog.csdn.net/qq_36391075/article/details/79475030
今日推荐