MVP概述
MVC
View: 对应于布局文件
Model: 业务逻辑和实体模型
Controllor: 对应于Activity
但是View对应于布局文件,其实能做的事情特别少,实际上关于该布局文件中的数据绑定的操作,事件处理的代码都在Activity中,造成了Activity既像View又像Controller,使得Activity变得臃肿。
MVP
而当将架构改为MVP以后,Presenter的出现,将Actvity视为View层,Presenter负责完成View层与Model层的交互。现在是这样的:
View: 对应于Activity,负责View的绘制以及与用户交互
Model: 业务逻辑和实体模型
Presenter: 负责完成View于Model间的交互
总结:MVP模式减少了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理,模块职责划分明显,层次清晰。与之对应的好处就是,耦合度更低,更方便的进行测试。
区别
MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的。
简单演示
Model层
实体类User
1 | public class User { |
接口
1 | public interface LoginModel { |
接口实现类
1 | public class LoginModelImpl implements LoginModel { |
View层
接口
1 | public interface LoginView { |
接口实现类
1 | public class LoginActivity extends AppCompatActivity implements LoginView, View.OnClickListener { |
View层实现Presenter层需要调用的控件操作,方便Presenter层根据Model层返回的结果进行操作View层进行对应的显示。
Presenter层
Presenter是用作Model和View之间交互的桥梁。
接口如下:
1 | public interface OnLoginFinishedListener { |
当Model层得到请求的结果,需要回调Presenter层,让Presenter层调用View层的接口方法。
1 | public interface LoginPresenter { |
登陆的Presenter 的接口,实现类为LoginPresenterImpl,完成登陆的验证,以及销毁当前view。
1 | public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener { |
总结
View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有View层的Interface的引用以及Model层的引用,而View层持有Presenter层引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的引用,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载情况,最后Presenter层再调用View层的接口将加载后的数据展示给用户。
缺点
P层与V层是通过接口进行交互的,接口粒度不好控制。粒度太小,就会存在大量接口的情况,使代码太过碎版化;粒度太大,解耦效果不好。同时对于UI的输入和数据的变化,需要手动调用V层或者P层相关的接口,相对来说缺乏自动性、监听性。
MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。
MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI
V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了
复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。