App下载 微信公众号

MVP架构设计【Android】

技术 · 移动开发 · Android/ 作者【吾非言】/ 发布于2018-3-17/ 2.16k次浏览
2018 3/17 10:27
摘要: 框架模式不是一门写代码的学问,而是一门管理与组织代码的学问。其本质是一种软件开发的模型。与设计模式不同,设计模式是在解决一类问题时总结抽象出的公共方法(工厂模式,适配器模式,单例模式,观察者模式……),他们与某种具体的技术栈无关。一种框架模式往往使用了多种设计模式,切不要把他们的关系搞混。

精辟句:什么叫燃烧自己,温暖别人,就是火葬场里烧锅炉。

伴职创作

MVC简介

在移动没有出现之前,大家一直使用的MVC,MVC是80年代的架构模式,但是但是出现一直没有火起来,后台出现了SSM,SSH等后台框架,MVC才得到很好地发挥。

MVC全称是Model - View - Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC是一种框架模式而非设计模式,GOF把MVC看作是3种设计模式:观察者模式、策略模式与组合模式的合体,而核心是观察者模式。简而言之,框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。

MVC结构图

  • View:传送指令到Controller。
  • Controller:完成业务逻辑后,要求Model改变状态。
  • Model:将新的数据发送到 View,用户得到反馈。

MVP简介

MVC在后台中使用的相当好,但是当在移动端使用MVC却不是那么回事,在移动端通常会把Activity/Fragment视作Controller,在项目较小的时候,Activity/Fragment所写代码并不是很多,所以在感觉上还好,但是一旦代码量上来的时候,就会感觉Activity/Fragment所写代码太多,显得十分臃肿。在Activity/Fragment中既有VC交互,而且还有MC交互和MV交互,这样使项目维护起来难度大了很多。

基于以上等等原因,于是MVP架构在最近两年出现了。所说MVP是MVC演化版本,但是两者之间还是有很大的区别,主要区别是在MVP中去除了MV交互,Activity/Fragment属于View层。

MVP和MVC对比图

MVP模式会解除View与Model的耦合,有效的降低View的复杂性。同时又带来了良好的可扩展性、可测试性,保证系统的整洁性和灵活性。

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

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 – 数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。

MVP设计与封装

在实现之前,首先看看Google MVP Demo

项目结构分析

假设在MainActivity中要显示一个ListView列表数据。如果采用MVP架构,就必须有View,Presenter和Model三层。

一、View:创建IMainView接口,定义对所有视图控件操作方法,在MainActivity实现该接口。
二、Model:创建PersonModel接口,定义对数据处理的操作方法,在PersonModelImpl类中实现。
三、Presenter:创建MainPresenter类,实现视图控件和数据绑定。

MVC项目结构图:

MVC项目结构图

Model层:

1、Person - Java Bean文件,保存人物相关信息:

/**
 * 人物类
 * Created by 邹峰立 on 2018/3/16.
 */
public class Person {
    private String name;
    private String address;

    public Person() {
        super();
    }

    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

2、PersonModel - 定义数据操作方法:

/**
 * 人物 model 接口
 * <p>
 * Created by 邹峰立 on 2018/3/16.
 */
public interface PersonModel {

    /**
     * 获取人物消息列表
     */
    void getPersonList(PersonModelListener personModelListener);

    // 定义回调接口 - 避免网络数据延迟
    interface PersonModelListener {
        void onComplete(ArrayList<Person> list);
    }

}

3、PersonModelImpl - PersonModel接口实现类:

/**
 * 人物接口实现类
 * Created by 邹峰立 on 2018/3/16.
 */
public class PersonModelImpl implements PersonModel {

    // 从本地/网络访问获取数据
    @Override
    public void getPersonList(PersonModelListener personModelListener) {
        ArrayList<Person> list = new ArrayList<>();

        list.add(new Person("张三", "张三张三张三张三张三张三张三张三张三张三张三"));
        list.add(new Person("李四", "李四李四李四李四李四李四李四李四李四李四李四"));
        list.add(new Person("王五", "王五王五王五王五王五王五王五王五王五王五王五"));
        list.add(new Person("赵六", "赵六赵六赵六赵六赵六赵六赵六赵六赵六赵六赵六"));
        list.add(new Person("钱七", "钱七钱七钱七钱七钱七钱七钱七钱七钱七钱七钱七"));
        list.add(new Person("孙八", "孙八孙八孙八孙八孙八孙八孙八孙八孙八孙八孙八"));
        list.add(new Person("周九", "周九周九周九周九周九周九周九周九周九周九周九"));
        list.add(new Person("吴十", "吴十吴十吴十吴十吴十吴十吴十吴十吴十吴十吴十"));

        if (personModelListener != null)
            personModelListener.onComplete(list);
    }

}

Presenter层:

1、BasePresenter - Presenter基类:

/**
 * Presenter基类
 * <p>
 * T 视图实现接口
 * <p>
 * Created by 邹峰立 on 2018/3/16.
 */
public class BasePresenter<V> {

    WeakReference<V> mViewRef;// 虚引用

    // 绑定mViewRef
    public void attachView(V view) {
        mViewRef = new WeakReference<>(view);
    }

    // mViewRef解绑
    public void detachView() {
        mViewRef.clear();
    }
}

2、MainPresenter - 实现Model和View的交互:

/**
 * 人物 Presenter
 * Created by 邹峰立 on 2018/3/16.
 */
public class MainPresenter<T extends IMainView> extends BasePresenter<T> {

    // model层
    private PersonModel personModel = new PersonModelImpl();

    // 绑定数据
    public void bindData() {
        if (mViewRef.get() != null) {
            mViewRef.get().showLoadToast();
            if (personModel != null) {
                personModel.getPersonList(new PersonModel.PersonModelListener() {
                    @Override
                    public void onComplete(ArrayList<Person> list) {
                        mViewRef.get().showData(list);
                    }
                });
            }
        }
    }
}

View层:

1、IMainView - 定义MainActivity中相关控件操作方法:

/**
 * 人物 界面 接口
 * Created by 邹峰立 on 2018/3/16.
 */
public interface IMainView {

    // 展示加载数据Toast
    void showLoadToast();

    // 展示数据(使用回调的方式还回数据)
    void showData(ArrayList<Person> list);
}

2、BaseActivity - Activity基类:

/**
 * Activity 基类
 * Created by 邹峰立 on 2018/3/16.
 */
public abstract class BaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity {

    T basePresenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        basePresenter = initPresenter();
        basePresenter.attachView((V) this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        basePresenter.detachView();
    }

    // 初始化Presenter
    protected abstract T initPresenter();
}

3、MainActivity - IMainView接口的实现类,视图显示类:

/**
 * MVP构架实践
 */
public class MainActivity extends BaseActivity<IMainView, MainPresenter<IMainView>> implements IMainView {
    private ListView listView;
    private MainLvAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = findViewById(R.id.listview);

        basePresenter.bindData();
    }

    @Override
    protected MainPresenter<IMainView> initPresenter() {
        return new MainPresenter<>();
    }

    @Override
    public void showLoadToast() {
        Toast.makeText(this, "加载数据...", Toast.LENGTH_LONG).show();
    }

    @Override
    public void showData(ArrayList<Person> list) {
        setAdapter(list);
    }

    // 自定义setAdapter
    public void setAdapter(ArrayList<Person> list) {
        if (adapter == null) {
            adapter = new MainLvAdapter(MainActivity.this, list);
            listView.setAdapter(adapter);
        } else {
            adapter.reflashData(list);
        }
    }
}

4、MainLvAdapter - ListView的适配器:

/**
 * 人物Adapter
 *
 * Created by 邹峰立 on 2018/3/16.
 */
public class MainLvAdapter extends BaseAdapter {
    private Context context;
    private LayoutInflater inflater;
    private ArrayList<Person> mDatas;

    public MainLvAdapter(Context context, ArrayList<Person> list) {
        this.context = context;
        this.inflater = LayoutInflater.from(context);
        this.mDatas = list;
    }

    public void reflashData(ArrayList<Person> list) {
        this.mDatas = list;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public Object getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.activity_main_lv_item, parent, false);
            holder.nameTv = convertView.findViewById(R.id.tv_name);
            holder.addressTv = convertView.findViewById(R.id.tv_address);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        Person person = mDatas.get(position);
        holder.nameTv.setText(person.getName());
        holder.addressTv.setText(person.getAddress());
        return convertView;
    }

    static class ViewHolder {
        TextView nameTv, addressTv;
    }
}

最终效果图:

最终效果图

MVP结构不一定是最好的结构,相对于MVC而言,可能在结构上清晰一些,但也要针对不同的项目以及你目前处于什么样的一个项目组,所以并不能说MVC比MVP差,或者说MVP比MVC好。

Github地址

微信公众号:伴职创作

感谢您使用伴职平台,如有侵权,请投诉删除!

全部评价

最新
查看更多评论 加载

猜你喜欢

换一批