在我Android开发的经历来看,Android软件流行的设计架构大体上的经历过MVC-MVP-MVVM这个历程。 MVP和MVVM其实都可以看做是MVC的变体,三者的目的都是相同的,那就是隔离层级,减少耦合。
MVC
M代表Model,V代表View,C代表Controller。 MVC历经发展,针对各种不同的情景,衍生出了许多变体,而每种变体的结构都是不尽相同的。网上对于MVC的解法千差万别,个人看法其实没有谁对谁错,只是针对的变种不同而已。
我对于这个问题纠结了很久:MVC结构到底是什么样的?这个问题众说纷纭,有的人认为View和Model应该是完全隔绝,有的人认为View要靠Model来更新数据;有的人认为MVC是单向循环的模式,有的人认为MVC是以Controller为主导,View和Model被动更新的模式;诸如此类。而MVC结构图也是千般万种,各不相同,很容易让人迷失在其中。
说一些题外话。在我看来,软件架构设计的初衷是为了让软件结构更加清晰,降低开发的复杂度。换句话说,就是减熵。只要达到这个目的,那么就不需要纠结它到底是不是正确的。不应该为了设计架构而设计,也不应该为了看上去高大上或者别人都这么做而进行设计,而是需要的是符合实际情况、能解决真实问题的架构。一个总共不超过10个用户的系统,使用淘宝亿级并发的架构,即使再高大上,不过是牛刀杀鸡罢了。而我们写的所有代码,设计的所有架构,开发的所有软件,都是为了解决实际问题的,是不可能脱离现实存在的。随着系统体量的增大,软件的开发和维护的难度也会随之增大,代码也会变得混乱不堪。MVC将整个系统横向分离出了视图、业务逻辑、数据三部分,每一部分各司其职,这样一定程度上降低了整个系统的复杂度。
正因为架构设计是为了解决实际问题,所以造成了在不同的场景MVC的结构也有所不同。
一个典型的MVC结构图如下所示,来自阮一峰的博客: !一个典型的MVC结构图
这个图很好的说明了MVC架构的事件传递过程。 > 用户在View层做了一些操作,然后事件传递给Controller层;Controller层接收事件,完成业务逻辑,然后更新Model层状态,事件传递给Model层;Model层更新状态之后,通知View层显示新的数据,事件又到达了View层。
必须要指出的是,但是事件传递过程并不代表方法调用过程,具体的实现因实际情况而异。代表事件传递过程的结构图和具体实现的结构图是两码事,可以把前者看做是目的,而把后者看作是为了达到目的的手段。手段是灵活的,是可以变的,但是最终的目的是不变的。也就是说,无论具体实现如何,只要能够实现MVC事件传递的目的,那就是一个合理的MVC架构。
下面是具体实现的部分。
一般来说,在实践中,Model不持有Controller和View的实例,Controller也不持有View的实例。也就是说,Controller对View、Model对Controller和View都是无感知的。
对于Model层通知View层的更新,有两种典型的方式,分别是同步模式和观察者模式。 第一种同步调用,View调用Controller,Controller调用Model,Model进行底层数据更新,然后依次返回所需数据;第二种观察者模式,View将一个监听器(一般是通过Controller)传递给Model,当Model进行数据更新时会向所有注册的监听发送通知,View收到通知就可以进行更新了。
MVP
MVP是MVC的演化版本,完全可以看做MVC的一种变体。 MVP和MVC的唯一区别是Model通知View数据更新的方式——在MVC中,View与Model以观察者模式相联系;而在MVP中,View与Model彻底断了联系,取而代之的是View和Presenter双向持有,而Presenter作为观察者对Model进行观察,监听到变化直接调用View的方法来使其更新。这样一来,View和Model就彻底解绑了。
MVP相比MVC有什么优势呢?网上有很多文章都在说这个,但是十之八九都是复制粘贴的,并没有说到点子上。 MVP相比MVC的最大优势自然是View和Model的解耦,毋庸置疑。但是这样做的好处是什么?好处在于,View层彻底从数据中解脱出来,不用再关心数据的显示,而把处理数据的任务交给Presenter。这么一来,View层可以把重心放在与用户的交互上,以期获取更好的用户体验。 然而,MVP带来的好处是有代价的——那就是View和Presenter的耦合更严重了——更不说需要定义大量冗余的接口,虽然可以通过插件一键生成,但是产生的代码量增加是肉眼可见的。
在Android中,一个典型的MVC流程是这样的: !Android中的MVC
而MVP流程是这样的: !Android中的MVP
其实在MVC中,View和Model并没有耦合的很严重,Controller也完全可以进行数据的处理——而MVP无非就是把setText从View中搬到了Presenter中。MVC也可以让Activity和Fragment作为纯粹的View,这也是完全是行得通的,并不会导致一个过于臃肿的类——如果Controller过于庞大,Presenter也会一样,这时候应该考虑的是拆分功能模块,而不是从MVC换到MVP。 总之,从我个人角度来看,MVP相对于MVC,不管从耦合度、结构的清晰度还是开发维护的难度上来说,并没有质的提升,反而造就了VP的紧耦合,以及大量的冗余接口——不过不得不说,MVP通过契约接口定义View和Presenter的功能,这个思想是很香的,至少能够让人一眼就看出这个模块的大致功能。换句话说,MVP能办到的事儿,MVC也能;反之亦然。二者在实际开发中并没有什么太大的差别。 在实践中,使用MVP而不是MVC,主要原因还是