MVC、MVP、MVVM
MVC ,MVP 和MVVM 都是常见的软件架构设计模式(Architectural Pattern ),它通过分离关注点来改进代码的组织方式。不同于设计模式(Design Pattern ),只是为了解决一类问题而总结出的抽象方法,一种架构模式往往使用了多种设计模式。
architectural [?ɑ?rk??tekt??r?l] 建筑学的,建筑上的 pattern [?p?t?rn] 模式,方式
MVC 、MVP 和MVVM 不同部分是C(Controller) 、P(Presenter) 、VM(View-Model) ,而相同的部分则是MV(Model-View) 。Model 层用于封装和应用程序的业务逻辑相关的数据以及对数据的处理方法。View 作为视图层,主要负责数据的展示。
1 MVC
通过Model&View 完成了数据从模型层到视图层的逻辑。但对于一个应用程序,这远远是不够的,还需要响应用户的操作、同步更新View 和Model 。于是,在MVC 中引入了控制器Controller ,让它来定义用户界面对用户输入的响应方式,它连接模型和视图,用于控制应用程序的流程,处理用户的行为和数据上的改变。
- 模型层(
Model ):用来存储业务的数据,一旦数据发生变化,模型将通知有关的视图。Model 是与View 无关, 而与业务相关的。对数据库的操作、对网络等的操作都应该在Model 里面处理,当然对业务计算等操作也是必须放在的该层的; - 视图层(
View ):一般采用XML 文件进行界面的描述`; - 控制层(
Controller ):Android的 控制层的重任通常落在了众多的Activity 的肩上;
MVC 允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View 的操作交给了Controller 处理,在Controller 中响应View 的事件调用Model 的接口对数据进行操作,一旦Model 发生变化便通知相关视图进行更新。
随着界面及其逻辑的复杂度不断提升,Activity 类的职责不断增加,以致变得庞大臃肿。
2 MVP
当我们将Activity 复杂的逻辑处理移至另外的一个类(Presenter )中时,Activity 其实就是MVP 模式中的View ,它负责UI 元素的初始化,建立UI 元素与Presenter 的关联(Listener 之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter 处理)。
MVP 的Presenter 是框架的控制者,承担了大量的逻辑操作,而MVC 的Controller 更多时候承担一种转发的作用。因此在APP 中引入MVP 的原因,是为了将此前在Activty 中包含的大量逻辑操作放到控制层中,避免Activity 的臃肿。
- 模型层(
Model ):负责存储、检索、操纵数据,有时也实现一个Model interface 用来降低耦合; - 视图层(
View ):负责显示数据,并向Presenter 报告用户行为。与用户进行交互,在Android 中体现为Activity ; - 业务逻辑层(
Presenter ):负责逻辑处理,从Model 拿数据,回显到UI 层,响应用户的行为;
google todo-mvp 加入契约类来统一管理View 与Presenter 的所有的接口,这种方式使得View 与Presenter 中有哪些功能,一目了然
优点:
- 分离视图逻辑和业务逻辑,降低了耦合,修改视图而不影响模型,不需要改变
Presenter 的逻辑。模型与视图完全分离,我们可以修改视图而不影响模型; - 视图逻辑和业务逻辑分别抽象到了
View 和Presenter 的接口中,Activity 只负责显示,代码变得更加简洁,提高代码的阅读性; Presenter 被抽象成接口,可以有多种具体的实现,所以方便进行单元测试;
Presenter 是通过interface 与View(Activity) 进行交互的,这说明我们可以通过自定义类实现这个interface 来模拟Activity 的行为对Presenter 进行单元测试,省去了大量的部署及测试的时间(不需要将应用部署到Android 模拟器或真机上,然后通过模拟用户操作进行测试)
缺点:
- 那就是对
UI 的操作必须在Activity 与Fragment 的生命周期之内,更细致一点,最好在onStart() 之后onPause() 之前,否则极其容易出现各种异常,内存泄漏; Presenter 与View 之间的耦合度高,app 中很多界面都使用了同一个Presenter 。一旦需要变更,那么视图需要变更了;
MVP 如何设计避免内存泄漏?
MVP 模式在封装的时候会造成内存泄漏,因为Presenter 层,需要做网络请求,所以就需要考虑到网络请求的取消操作,如果不处理,Activity 销毁了,Presenter 层还在请求网络,就会造成内存泄漏。
如何解决MVP 模式造成的内存泄漏?只要Presenter 层能感知Activity 生命周期的变化,在Activity 销毁的时候,取消网络请求,就能解决这个问题。
下面开始封装Activity 和Presenter 。定义IPresenter 声明Activity(Fragment) 生命周期中的各个回调方法:
public interface IPresenter {
<U extends IUI> void init(BaseActivity activity, U ui);
void onUICreate(Bundle savedInstanceState);
void onUIStart();
void onUIResume();
void onUIPause();
void onUIStop();
void onUIDestroy();
void onSaveInstanceState(Bundle outState);
void onRestoreInstanceState(Bundle savedInstanceState);
}
封装BaseActivity 拥有一个protected P mPresenter 实例,类型写成泛型,protected 修饰,子类实现构造方法中,对mPresenter 进行实例化:采用反射的形式(避免让子类进行实例化,繁琐):
public abstract class BaseMVPActivity<P extends IPresenter> extends BaseActivity {
protected P mPresenter;
public BaseMVPActivity() {
this.mPresenter = createPresenter();
}
protected P createPresenter() {
ParameterizedType type = (ParameterizedType) (getClass().getGenericSuperclass());
if (type == null) {
return null;
}
Type[] typeArray = type.getActualTypeArguments();
if (typeArray.length == 0) {
return null;
}
Class<P> clazz = (Class<P>) typeArray[0];
try {
return clazz.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onDestroy() {
mPresenter.onUIDestroy();
super.onDestroy();
}
}
封装BasePresenter 。定义BasePresenter ,页面销毁的回调里面。处理网络请求定义一个集合,把每次网络请求装载到集合里面,在页面销毁的时候,取消所有的网络请求。防止内存泄漏。
public abstract class BasePresenter<U extends IUI> implements IPresenter {
@Override
public void onUIDestroy() {
}
}
MVC 与MVP 区别
View 与Model 并不直接交互,而是通过与Presenter 交互来与Model 间接交互。而在MVC 中View 可以与Model 直接交互。MVP 隔离了MVC 中的M 与V 的直接联系后,靠Presenter 来中转,所以使用MVP 时P 是直接调用View 的接口来实现对视图的操作的。
3 MVVM
MVVM 可以算是MVP 的升级版,其中的VM 是ViewModel 的缩写,ViewModel 可以理解成是View 的数据模型和Presenter 的合体,ViewModel 和View 之间的交互通过Data Binding 完成,而Data Binding 可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity 的压力。
DataBinding 用来实现View 层与ViewModel 数据的双向绑定,Data Binding 减轻原本MVP 中Presenter 要与 p 和 View 互动的职责
- 模型层(
Model ):即数据模型,用于获取和存储数据; - 视图模型层(
ViewModel ):与Presenter 大致相同,都是负责处理数据和实现业务逻辑,但ViewModel 层不应该直接或者间接地持有View 层的任何引用; - 视图层(
View ):包含布局,以及布局生命周期控制器(Activity/Fragment );
MVVM 的本质是数据驱动,把解耦做的更彻底,ViewModel 不持有View 。
View 产生事件,使用ViewModel 进行逻辑处理后,通知Model 更新数据,Model 把更新的数据给ViewModel , ViewModel 自动通知View 更新界面,而不是主动调用View 的方法
MVVM 的优点:
核心思想是观察者模式,它通过事件和转移View 层数据持有权来实现View 层与ViewModel 层的解耦。
- 耦合度更低,复用性更强,没有内存泄漏;
- 结合
Jetpack ,写出更优雅的代码;
缺点:
ViewModel 与View 层的通信变得更加困难了,所以在一些极其简单的页面中请酌情使用,在使用MVP 这个道理也依然适用。
参考
https://blog.csdn.net/lihaoxiang123/article/details/78977181
https://blog.csdn.net/caijunfen/article/details/78478438
|