这些年,参与的项目大大小小应该有六七个。所采用的项目架构,也是从 MVC 到 MVP ,后来使用 ReactNative 进行跨平台开发,再到后来回到原生,使用 MVVM。本节,打算聊一聊我的项目架构的演变之路。
MVC
M, Model,主要负责进行数据访问,产生数据;C,Controller,主要负责对接 View 和 Model,将 Model 反映到 View 上,或者响应 View 上的动作,修改 Model,处理业务;V,即 View,主要负责 UI 渲染。
上图来自维基百科。我们可以看到一个典型的 MVC 模式下的数据流向。上图中,View 监听 Model 的数据变化,然后进行 UPDATES 工作,这其中也会有业务逻辑处理。事实上,有些时候我们还需要对 Model 层的数据做进一步处理然后再做前端展示,这也是部分业务逻辑。
所谓架构只是一种设计理念,目的就是在于保持逻辑的清晰,面向改变易扩展,功能易复用。对于 MVC 模式而言,看上去各司其职,请求数据的产生数据;负责逻辑的处理逻辑,负责渲染的进行渲染,清晰明了。
然而,View 层对 Model 有着很强的依赖。为了能够使得 Model 发生的变化及时反映到到 View 上,View 需要注册成为观察者到 Model 上。鉴于这种关系,View 、 Model 需要互相持有对方的引用。
首先,这种相互持有引用会导致层次的独立性、可重用性要降低一些,而且这种行为也是危险的,暴露更多的能力给 View,可能使得部分本应在 Controller 处理的逻辑放在 View,因为这样做确实更加快捷方便。这样做也会带来一个很严重的问题:View 会客串 Controller 的角色,从而越来越臃肿,解耦能力越来越弱。
MVP
使用 MVC 没多久,同事建议组长采用 MVP 开发模式,于是,就是这么快的就跳转到了 MVP 的阵营。当时最感兴趣的还是这种架构中突出的对接口的应用,面向接口的编程思想。
面向接口的编程,实际上是 Java 开发一直所倡导的。优势在于解耦,降低依赖关系。但是也会让开发工作更加复杂。
上图同样来自维基百科。相较于 MVC 模式,它切断了 View 层和 Model 层的直连。Model 和 Presenter 之间, Presenter 和 View 之间相互暴露接口,并通过接口相互访问,接口构成了它们通信的通道。与 MVC 类似, Modle 负责数据访问和处理;Presenter 像胶水一样,把 Model 和 View 绑在一起,它主要处理业务逻辑,对 View 提供处理好的数据,对 Model 请求数据;View 处理 UI 渲染。
后来的开发过程中,很少使用 MVC,当然并不是因为觉得它比 MVP 差。更多的,自己是想增强接口使用的意识,以及对新事物的一种探索欲。现在想想,其实它们更多的是理念上的不同,如果控制的足够好,各有千秋吧。下面我们就来比较一下。
MVC vs MVP
这两种结构,都体现了良好的解耦理念。将一个需求拆分成数据访问模块、UI渲染模块、业务处理模块,相对独立,分工明确,各谋其政。同时,各个模块之间又可以在一定程度上相互组合,尽可能地进行功能复用。但是,在具体使用上,我觉得还是有一些偏好。
保证结构的清晰是一件非常重要的事,对此,大多数情况下宁愿牺牲性能。这一点上我认为 MVP 要比 MVC 做的好,职责划分的更加清晰。Activity 只负责渲染,很清爽;当然,这就意味着更多的处理逻辑需要搬到 Presenter 中去;Model 只负责向 Presenter 提供数据支持。为了保证逻辑的清晰,整个过程却会显得复杂,有些地方甚至没必要。View 层明明只是需要改一下 Model 的数据,都需要 Presenter 代劳。显然,这种清晰性牺牲了高效。
结构上的清晰,职责上分工更加明确,更细,也应该就意味着更好的复用性,更加灵活。但是,同样这也未必总是需要的。如果一个需求交互不多,Presenter 可能就会非常小,又何必将一个文件能够搞定的事一定要分成三个文件去完成?
MVVM
MVVM 是由 MVP 演化而来的。我觉得它主要解决了 MVP 没有很好解决的两个问题:
- 对于 MVP 的 Presenter 层,由于要处理所有业务逻辑,又要完成 Model 和 View 的沟通,最终可能也会非常臃肿。
-
通常情况下,我们总是要通过 findViewById 找到控件,然后进行数据填充,如果一个页面很复杂,需要填充的数据很多,这样在 View 层会显得很不优雅。
这样,就交给 MVVM 来解决吧。
上图(来自维基百科)中很好的解决了这两个问题。ViewModel 集合了 Presenter 的能力,同时兼顾了 View 需的数据基础。它将数据直接绑定到 View上,这种绑定是一种双向绑定,即数据的变化会自动导致 UI 的刷新,而 UI 上的动作,同样会自动调用响应的绑定的函数修改数据。
Android 所提供的 DataBinding 技术很好的体现了这一点。之前翻译过一篇官网上关于 DataBinding 的介绍,感兴趣的可以看一下。现在 View 层可以更加清爽,不用再为了填充数据而找出所有的 View,一个一个填充,而 View 也会由于某个用户动作而自动回调修改数据,这一切都是自动完成的。当然,有利必有弊,这种框架的使用,首先需要我们去了解它的特性;而且自动完成,未必会有我们手动完成效率高,多半会牺牲部分性能。
小结
架构, 一种理念,一种思想,一个工具。它的目的,旨在帮助我们更好地面对、处理变化;更加清晰地认知我们正在做什么。
工具是有了,这只是一个基础。更为关键的我觉得还是对这种工具的把控能力。因此,也并非是说你使用了 MVVM , 你的项目应对变化的能力就一定会比 MVC 好。对于需求的理解,将需求进行抽象的能力,以及对于技术扎实的能力,这些都将会对架构的把控提出挑战。