Android框架MVC/MVP/MVVM记录

365 阅读7分钟

Android中的框架由最初的MVC进化到MVP,在超进化到MVVM,这里是我对于这些框架的理解记录。我喜欢举例子来理解抽象的概念。

把MVC当作是一个2个人的创业公司,一个搞后勤,一个搞前台事物,只不过这个搞前台的人能力高,搞后勤的人能力弱(包括认知能力),所以在现阶段就是搞前台的人做了主要的工作,对应的就是VC的职责都在被搞前台的处理了,在代码中的表现就是所有的视图显示和逻辑控制都写在页面中,导致代码耦合性强,代码混乱,臃肿,扩展性和维护性难,可读性差。

MVP相当于2个人创业到一段时间后因为业务需求需要增加人手,招了一个人来分担搞前台的一部分压力,这个新人负责处理变现层的逻辑业务对应的就是presenter,搞前台的就只负责页面显示就可以了,搞后勤的能力加强了,以前只是提供数据实体类,现在负责业务逻辑处理,负责处理数据(注意数据处理工作还可以进行分层处理,对外P层来说他只需要数据,至于数据是怎么来的,做了些什么处理P层不关心),例如在一个复杂的业务模块中,model层是所有业务层的最上层封装,

关于MVC/MVP/MVVM的一些错误认识

这就好比一个公司在创业前期靠的是流程简介,组织结构简单,当发展到大型规模之后就需要对组织规模进行扩充,对于组织结构进行细化处理,问题的处理方式需要流程化,但是这样也无形中牺牲了一些灵活性,对于代码架构设计要考虑实际的情况,灵活的变换处理。

不管VC/VP/VVM怎样变化,M层的职责是不会变化的,也是最重要的,Android客户端做的就是将Model--->View的映射,不管传递到view层的数据页面显示怎样变化,这个数据的获取与处理都归属于model层业务逻辑中。当业务逻辑复杂时,model层变得复杂,就需要解决复杂问题,方法可以看下面的内容。这里做一种处理思路记录。

提问: 我之前和楼主想法一样,把逻辑放在了 model 层,但是发现这样中间层基本成了摆设,特别是用 ViewModel 时,基本就是转发一下上下两层的数据和事件,中间简单坐下变换。 而 model 层要完成数据请求(包括区分网络、数据库和文件等)、数据转换(因为业务逻辑不一定作用在原始数据上)、业务逻辑和通知上层等功能,很不优雅。 后来仔细想了想,客户端造成的任务就是 model -> view 的一个映射而已,如果业务逻辑简单,完全可以不要中间层。 在我看来,中间层的引入就是为了解决复杂业务逻辑下 model 到 view 的映射问题。既然中间层是为了解决复杂业务问题,业务逻辑自然就应该放在中间层。 以上只是个人经验+习惯,不喜勿喷

回答: Model层处理业务逻辑这一点是万万不能改变的。对于ViewModel层过于简单以至于“成了摆设”,我觉得可能有这么几个原因: 一、View层处理了过多的表现层逻辑导致ViewModel无事可做,不管是MVVM还是MVP目前的趋势都是让View层处理尽量少的表现层逻辑; 二、很多表现层逻辑让View和ViewModel之外的类处理了,比如一些Adapter类; 三、视图层的交互逻辑(即表现层逻辑)相对比较简单,加上架构组件的引入也在一定程度上简化了表现层逻辑的处理,比如数据绑定、生命周期处理,这时候ViewModel的简洁是应该的,这体现了架构组件的意义。 而Model层复杂的解决方法并不是将部分业务逻辑上提到ViewModel中,这样就模糊了边界,如果ViewModel既处理业务逻辑又处理表现层逻辑,那么ViewModel的职责就变得不明确,如果ViewModel只处理业务逻辑,让View处理表现层逻辑,这就违背了MVVM的初衷(实际上ViewModel处理业务逻辑就是违背初衷的)。 Model层复杂的解决方法可以有: 一、将数据请求、数据转换等非业务逻辑分离成单独一层放在Model层之下; 二、将真正复杂的业务逻辑再进一步细分,分层处理或者在同一层分类处理,即Model层内部可能包含多个垂直的细分层,也可能包含多个水平的细分类用来处理复杂的业务逻辑。

面试问题:说说MVP

Android MVP架构从入门到精通-真枪实弹

1:MVP的核心作用是为了解决MVC架构中View层和Controller层耦合性高的问题。

2:MVP是怎样降低耦合性的?(怎样实现?)

将View层和和原来的显示控制层逻辑处理做强制分离,引进Presenter来处理表现层的业务逻辑代码,View层只处理页面显示代码,耦合性就降低了,理论上就解决了MVC的问题                                

最简单的流程如下:

View层中处理页面显示效果,并持有P层对象(注意此处是P层的对象不是引用),Presenter的构造方法中直接创建一个该页面对应的Model层对象,P层可以调用M层方法,当用户在页面上触发了某个事件之后,View层将事件传递到P层中,P层处理表现层业务逻辑或者调用M层网络请求和数据处理之后通过回调将结果回调到P层,P层在通知View层改变页面,整个基本流程便走通了。

问题:上面的流程中P层如何控制V层改变页面效果呢?

V层是因为持有P层的对象,P层无法直接持有个Activity对象,为什么要持有对象呢?因为持有对象之后P层在需要改变View层页面时调用改变页面的方法了,那么可以这么说我们最终的目的是为了调用View层中改变页面的方法,而不是需要View层对象的全部,那这样的话我们可以写一个接口,这个接口中包含View层中改变页面的抽象方法,具体的实现交给View对象去实现,P层只需要持有这个接口的引用的就可以了,这样P层就能通知View层。同时我们知道利用接口解耦合,同样,View层持有的P层对象可以修改为接口,P层中对于M层的对象也可以改为引用接口,这这处理还存在问题

问题:V层和P层生命周期的问题处理

V层的生命周期要匹配到P层中去,写一个IPresenter接口处理P层与V层生命周期的匹配,IPresenter中有三个方法,绑定View,解绑View层,判断View和P层是否绑定,因为生命周期这部分功能是通用的,所以我们抽取出抽象的基类BasePresenter实现IPresenter接口,每一个具体页面的P层实现类都需要集成BasePresenter实现生命周期的绑定并且实现该页面对应的Presenter表现层逻辑接口。

问题:MVP优化问题

MVP会产生大量的接口,所以我们可以针对每个页面写一个Contract来统一管理接口,减伤部分文件的创建。该接口中包含View层的抽象方法,和P层的表现层业务抽象逻辑方法,这样看起来清晰明了,且减少了文件的创建。

另外我们出现的RelifeCycle是对生命周期的细致化处理。Dagger2是通过依赖注入来解决对象引用这种耦合性强的问题。