APP下载

浅谈专案架构重构:元件化与MVP

消息来源:baojiabao.com 作者: 发布时间:2024-05-02

报价宝综合消息浅谈专案架构重构:元件化与MVP

为什么要进行区域性架构重构

解决完全域性架构的优化,整个专案已经实现模组化,然而这样就足够了吗?来看一看模组内部是什么样的,先看一下相对于简单的模组:

看起来还挺干净利落的对吧?采用mvc模式,一个activity承载一个业务。那么当业务变得复杂且需要与其他activity共用又会变成什么样?以我们专案中相簿业务为一个例子。

可以看到,这个层次结构比上面的复杂了一些,在我们的专案中,有几个业务具有相簿业务,为了实现可复用性,我们抽取了共用的相簿业务Activity,提供一些相簿相关的基础业务和操作。由于校园业务的相簿又分视讯相簿和图片相簿,而这两个相簿又只有点选和界面的些许不同,大部分逻辑相同,于是又抽取了校园相簿的基础Activity。这是这个复杂业务的大致情况,实际为了复用,这里并不止抽取了这几个Activity,大概是一个不同业务就抽了一个共用的Activity,导致相簿这一块的程式码逻辑和结构层次极其复杂,混乱。

抽取共用的Activity确实提高了复用度,但是当业务复杂起来,就带来了严重的冗余问题,同时业务的不合理拆分容易造成开发时的混乱。

再看看mvc这块,在图中可能看不出什么端倪,但实际上,在复杂的业务模型下,view与model之间往往纠缠不清,view持有多个model,多个model又持有view,同时大量的controller程式码和view程式码糅合在Activity中,不仅使得Activity的程式码量剧增,难以维护,往往还带来了不少内存泄漏的问题。

为此,采用元件化来改善现有架构,并引入MVP模式优化业务逻辑的处理。

先来看看引入元件化+MVP的架构,能解决什么问题:

实现程式码上的解耦,减少冗余的Activity模组职责划分明显,层次清晰实现各通用功能的高复用性和灵活性通过元件组装的方式,使得整个模组层次结构分明元件可以作为独立工程开发,因此对功能的开发,测试不用再进行全专案编译解决在mvc模式容易因界面回拨导致内存泄漏的问题下面来看一下,元件化+MVP是什么样的架构。

什么是元件化与MVP

元件化:元件化模组化并不是同一个层次的概念,元件化的粒度更小,笔者更偏向于用Lib来形容一个元件。就比如我们常用的Picasso,这是一个图片载入元件,又如OkHttp是一个网络请求元件。这样子的单一功能或单一功能集的Lib,便是元件。

实现元件化即将专案中的业务功能进行细分,划分出粒度更小的通用功能元件,这些元件可以在多个专案中实现复用,而不再单单只归属于某一特定专案。

举个例子来说,笔者参与专案有个相簿模组,看似抽离了很多通用的Activity,好像可以在其他专案中复用,可实际上呢?仅仅只有最上层的一个Activity可以实现复用,其他Activity都与View强耦合。而最上层的Activity功能又是最少的,根本无法实现复用,只能说减少了一点程式码量。

对此,将整个相簿模组抽离成了一个图片展示元件

这个元件依赖于图片载入元件,也就是Picasso之类的框架,实现了通用的图片列表,图片九宫图,图片新增删除等展示功能。原来所有冗余的Activity全部弃用,只需实现一个承载特定业务逻辑的界面,并使用该元件进行展示即可。

MVP:对于MVP模式相信大家都不陌生,MVP模式是传统安卓MVC模式的改良版,将原本承担View和Controller功能的Activity改良为只承担View这一功能,引入Presenter作为View与Model层的中介,架设特定的业务逻辑。

引用一张经典MVP的图片来解释:(原文)

对于MVP模式,网上包括Google官方都有提出几种不同的实现方法,常见的有todo-mvp与mvp-clean等,其实对于MVP的实现方式,不同人有不同的见解,不同方式也适用于不同的专案,因此只要理解MVP的思想,以最适用自己专案的方式实现即可。在本专案中主要以todo-mvp为原型进行改良,实现了一套自己的MVP模式

如何实现元件化和MVP

如何实现元件化

对于元件化开发,从功能的角度,笔者将元件分为两种:功能型元件View型元件。简单的来说,View型元件一般比功能型元件多了View层的实现。

功能型元件

也就是日志元件、网络元件、图片载入元件等基础元件。这些元件一般不具备View,只负责提供逻辑功能,需要开发者自己实现特定的View来搭载这些功能。 对于功能型元件的实现大家应该都比较熟悉,就算没有实现过也应该用过各种第三方的开源元件。View型元件

而对于View型元件也就是笔者专案中的图片展示元件以及知乎的Matisse元件。这样的元件不仅仅具有逻辑功能,还附带View的实现。 对于知乎实现的Matisse元件,其采取的是Activity的方式来作为载体,暴露出该Activity的启动方法作为入口。这是大多数View元件会采取的实现方式。以Activity做为载体,那么实现过程与我们平时进行开发的过程差别不会很多,然而却不可避免的减少的了灵活性和复用性。并且只能通过继承来扩充套件其他功能,元件的通讯也十分局限。这也正是笔者专案一开始的实现方式。还有另外两种实现View型元件的方式,一种基于Fragment,另一个种基于Custom View。两种实现方式各有各有的优缺点。

基于Fragment的View元件

基于Fragment的实现类似于Matisse基于Activity的方式。一样的生命周期处理,同样可以套用MVP模式。实现过程与我们平时开发也不会差很多。最后只需要暴露Fragment的建立方式即可。

不同于Activity,采用Fragment使得整个元件灵活了许多。可以采用界面通讯,并同时保留了与Activity相应的生命周期处理。很好的划分了各个元件之间的界限,解决了复用和耦合的问题。

不过,采用Fragment作为主体,那么不可避免的就带了一系列碎片化的问题,包括旋转屏幕、状态改变、Fragment的重建等问题。

基于Custom View元件

首先要说的是这类Custom View不同于常见的自定义View,常见的自定义View往往不具有太多的非View逻辑操作。这类Custom View以自定义View为载体,具备自己的Model层和Presenter层。可以说是另类的MVP模式。

以图片选择元件为例子,我们需要的东西有:图片载入元件(Picasso)、获取本地图片的工具类(Model)、承载这两者的Custom View、以及协调CustomView和Model的Presenter。这个Custom View可以继承自RecyclerView或者ViewGroup,不同父类保留给外界使用者的特性不同,根据不同情况可以选择不同父类(如果希望保持足够多的列表特性给外界,那么可以继承自RecyclerView,如果不希望外界对内部干预过多,那么继承自ViewGroup)。而统筹这三者逻辑类似于Matisse,只不过Matisse以Activity为承载。

最后我们只需要将这个Custom View暴露给外界即可,其余逻辑由内部实现。这样的实现方式避免了采用Fragment而带来的碎片化问题,也很好的解决了复用和耦合的问题。不过也因此Custom View的生命周期难以管理,无法与Activity对应上,需另行处理。

管理元件

对于元件化,其实实现难点并不多,更多是理解元件化的思想和如何管理各个元件。对于管理元件而言,尤其是View型元件,网上有很多方案,有不少人建议用Router统一管理,元件化使用Router,有些大材小用。

对于元件化的管理,采用上传到私有Nexus仓库,直接通过Gradle依赖管理。

如何实现MVP模式

对于MVP模式,网上已经有很多文章进行解释,GitHub也有很多案例,这里简单介绍一下思想,更多详细建议学习官方DEMO

在MVP模式中,将架构分为三层:

View View层主要负责界面元素的展示,包括Button、TextView等。由XML和Activity / Fragment组成。前者主要负责静态界面布局,负责负责动态界面。Model Model层通常是MVP模式中最复杂的一层,主要负责资料的请求、读写。这一层往往可以分为本地资料和网络资料。Presenter Presenter是MVP模式中极其关键的一层,作为View和Model的管理者,也即是中介者。承载着相应的业务逻辑,接收来自View的请求,转换为对Model的请求,进而接收Model的回复,从而通知View进行重新整理。三个层次之间的关系如下

View接收使用者的触控事件,传递action给PresenterPresenter接收到action,执行对应的业务逻辑。如果涉及到资料请求,那么传送相应的request给ModelModel接收到request,进行本地或网络资料请求。待请求结束,返回对应的response给PresenterPresenter接收到Response,执行对应的业务逻辑。如果需要更新界面元素,那么通知View进行处理整个流程看起来十分清晰,实现也不难,需要注意的一点是要注意各个层次的呼叫关系。View层不能主动呼叫Model,Model亦不可呼叫View层。两者需要通过Presener作为桥梁。

再思考

其实对于区域性架构的重构,并没有太多的技巧,更多的是一种思想。

无论是元件化还是MVP,都是力求实现程式码层次的解耦,实现更高程度的复用,是我们的程式码更加优雅。

纵然使用元件化和MVP都会增加我们的程式码量和研发周期(稍微,可接受)。然而,这样的付出是值得的,但我们回观整个架构,会感觉一切都是可控的,不管是控制元件的管理,还是View、Model的管理,都十分灵活。

最后再看一下结合模组化重构完之后,整个专案的架构:

一目了然,整个App划分为多个业务模组,这些业务模组以Module的形式管理。对于每个Module需要使用的通用功能,也就划分为了元件,这些元件以Lib的形式管理,借由Gradle进行依赖管理。

而不管是模组亦或是元件,我们基本都采用了MVP的模式(部分简单的模组、元件除外)。这样便使得不管是整体架构,亦或是区域性架构,都十分灵活可管理。

2020-01-13 16:54:00

相关文章