前言
- 在说MVC和MVP,MVVM架构之前,我们先得理清楚什么是框架模式,什么时设计模式.
- 框架模式:通常是对代码的重用,用来对软件的设计进行分工.
- 设计模式:通常是对设计的重用,是小技巧,对具体的问题提出解决方案,以提高代码复用率,降低耦合度.
- MVP模式简单总结就是:Presenter与view和数据Dao层先建立链接实现抽象接口,内部实现业务逻辑和数据处理;
- View只负责数据显示和初始化.数据Dao负责数据模型和本地存储
- 其次,就是在使用过程中需要建立Presenter和Activity对象基类,用来在Activity生命周期中绑定二者,避免内存泄露
MVC模式
- 定义:model-view-controller.其分别代表的意思.
1.视图(view):用户界面
2.控制器(Controller):业务逻辑
3.模型(Model):数据保存 - 通信方式:
- 所有通信都是单向的.View 传送指令到 Controller,Controller 完成业务逻辑后,要求 Model 改变状态,Model 将新的数据发送到 View,用户得到反馈.
- 优点:理解容易,技术含量并不高,不便于维护.
MVP模式
- 定义:model-view-presenter
1.Presenter:交互中间人,作为沟通View和model的桥梁,它从model层检索数据后,返回给View层,使得View和model之间没有耦合,也将业务逻辑从View角色上抽离出来
2.View:用户界面,通常指activity\fragment或者自定义View类中,它含有一个presenter成员变量,需要实现一个逻辑接口,将View上的操作通过转交给presenter进行实现,最后presnter调用view逻辑接口将结果返回给view元素
3.model:数据的存储.封装了数据库DAO或者网络获取数据的角色,或者两种数据获取方式的集合.主要提供给presenter进行逻辑处理 - 通信方式:
- 各部分之间的通信,都是双向的
- View 与 Model 不发生联系,都通过 Presenter 传递
- View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里
- 优点:
1.理想化的MVP模式可以实现同一份逻辑代码搭配不同的显示界面.因为它们之间并不依赖于具体,而是依赖于抽象.
2.可以让UI界面和数据分离.业务逻辑和数据存储是紧耦合的,缺乏经验的工程师可能会将各种各样的业务逻辑塞入activity\fragment或者自定义View类中.业务逻辑和View元素严重的紧耦合在一起导致了类型膨胀的问题
MVVM模式
- MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致.
1.ViewModel的角色:业务逻辑处理,以及修改view或者model的状态.
- 唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式。
- MVVM模式优点类似adapter,
MVC,MVP,MVVM三者间对比
- MVC耦合性相对较高,用户可以向view\controller发送指令,controller相当于事件路由的作用,同时业务逻辑都部署在controller中,缺点是view可以直接访问model层,导致三者之间构成回路.
MVP模式案例
- 本案例是书上提供给读者的MVP模式的案例,笔者写了一下,稍稍有一点MVP这种模式解耦优于MVC的感觉,但实际开发没真正使用过此框架,可能以下自我总结有疏漏的地方,请各位辩证性的看待和指出,一切研究都是为了更好的学习嘛.
- View:即activity\fragment等,只做一些View的初始化工作,职责单一,功能简单,易于维护.其次与 Presenter中间类建立联系.并实现主界面ViewInterface的接口,用于Presenter回调View的操作
/**
* MVP架构模式demo
* @author max
*
*/
public class MainActivity extends Activity implements ViewInterface{
List<Model> models = new LinkedList<>();
Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
presenter = new Presenter(this);
}
private void initViews() {
}
@Override
public void showData(Model model) {
}
}
/**
* 主界面的逻辑接口
* 代表了View接口角色,用于Presenter回调View的操作
* @author max
* */
public interface ViewInterface {
public void showData(Model model);
}
- Presenter:中间人对象,用于view和model通信,主要持有的view显示层和model数据库操作层引用都是抽象而非具体,那么可以实现轻易的替换.
/**
* 中间人对象,用于view和model通信
* 从网络获取model数据省略
* @author max
* */
public class Presenter {
ViewInterface mInterface;
Model model = new Model();
public Presenter(ViewInterface sInterface){
this.mInterface = sInterface;
}
public void getDatFromWeb(){
}
}
- model层主要是数据实体,ModelDaoImpl主要封装封装的数据库操作Dao的操作,这里就不贴代码了.
- 最后文章提供了一个Prensenter和BaseActivity的基类,通过基类的声明周期函数来控制它与Presnter的关系,在oncreate建立view和Presenter联系,在onDestroy解除两者联系,避免内存泄露.
/**
* 中间基类,放置activity关闭,但Presenter一直持有activity强引用对象,从而造成内存泄露
* @author max
*
* @param <T> view角色要实现的接口类型
*/
public abstract class BasePresenter<T> {
protected Reference<T> mViewRef;
/**
* 与view建立关联
* @param view
*/
public void attachView(T view){
mViewRef = new WeakReference<T>(view);
}
/**
* 获取View
* @return
*/
protected T getView(){
return mViewRef.get();
}
/**
* 判断是否与View建立了关联
* @return
*/
public boolean isViewAttached(){
return mViewRef != null && mViewRef.get() != null;
}
/**
* 解除关联
*/
public void detachView(){
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
}
/**
* 通过基类的声明周期函数来控制它与Presnter的关系
* 在oncreate建立view和Presenter联系,在onDestroy解除两者联系,避免内存泄露
* @author max
*
* @param <V> View接口类型
* @param <T> Presenter的具体类型
*/
public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends Activity{
protected T mPrensenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPrensenter = createPresenter();
mPrensenter.attachView((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPrensenter.detachView();
}
protected abstract T createPresenter();
}
源码下载