-
需求场景
公司的老项目重构任务是要求把以前的ionic混合开发项目进行拆分,将大部分功能和主入口实现原生化,而商城这种业务变化较快的模块仍然保持H5方式展示。在第一版本的时候因为时间关系,只做了基础模块和主入口的原生化,剩下的大部分模块仍然是用老的coordova项目的代码打了一个aar包进来加载。也是在这个时候,因为项目中嵌入了大量配合coordova的代码,而这部分代码下个版本是注定要扔掉的,作为一个有强迫症的人,自然是不能容忍主项目里面有这些代码的,所以模块化的坑就这么挖起来了。
-
模块化开发的优势
一是结构清晰,各个模块的代码实现分离,不会搅在一起。在代码review或者二次开发的时候一目了然,不会满世界去找代码。
二是协同开发的时候更灵活,不用再等同组其他同事的模块开发完成后才能运行app,自己负责的模块稍加修改就可以当做主app直接跑起来。
三是便于维护。每个模块的代码、布局文件、资源文件可以随时从项目中通过gradle配置去除掉。 -
基本思路
公司接收的项目是一个货运平台app。按照功能划分,有货运模块、交易模块、货源模块、商城模块和个人中心。其中后两个是原项目的H5模块中的老代码,前三个是全部实现了原生化。所以基本结构就是原生入口,下分五个原生子页面。后两个原生子页面加载webview进行H5页面展示。
这里先附上一张基本的项目结构图。下面来说说这个项目的结构是怎么一步步整个成这样的。
1.基本结构
app模块是每个项目初始都有的,实质上仍然是一个module。Android Stuido项目中,我们和代码打交道的大部分时间都在module中。当然,具体的module机制我们不去深究,有时间可以另开一坑去研究。下面的三个module大家可以理解为java中的library,当然这样说不准确。
app作为主要的module,主要承担了应用启动以及最上层的通用逻辑。比如在这个例子中,应用启动、首页展示和模块切换的业务逻辑都在这个模块。
而下属的三个子模块承担了各自细分的业务,并且可以被app模块或者其他模块引用,每个模块只负责和考虑自己的业务。以此达到业务逻辑和代码分离的逻辑。按照之前的业务逻辑划分,项目结构可以先大致分为如下的结构:
2.系统层分离
当然,仅仅这样是不够的。因为这样有一个问题,在AS中,module的引用是单向的。如果A module引用了B module,那么对A来讲,B是可见的,B的所有公开功方法理论上都可以在A中使用,但是对B来说,A是不可见的。所以,相面这样的结构出现的问题就是我们有大量的底层通用方法都放在app模块中,对于子模块来讲是不可见的,子模块无法引用封装好的底层方法,例如网络请求,图片加载,文件拷贝等,这肯定是不行的。所以这个结构还得再优化。
按照module单向引用的原则,我们可以把公共底层通用方法单独分出来作为一个moduleBase,同时这个moduleBase也是最底层的module,保证对于其他module来说它都是可见的。这样还有一个好处就是这个moduleBase中的方法和配置大部分都是可以高度复用的。在新开其他项目的时候这个模块可以直接迁移到新项目中,而不用在为代码分离和剔除浪费时间。所以,项目的结构进一步细化成了如下的结构:
到这里,一个基本的结构就算完成了,但是这个结构仍然不完善。
3.公共层分离
上述的模块如果在使用中,有很大概率会遇到一个问题,部分的实体类、自定义view、布局文件或者资源文件在各个模块都需要用到,但是这些如果放在系统层的moduleBase里面,又会破坏系统层的通用性。所以,我们还需要一个公共层moduleCommon来专门提供上层业务逻辑模块的公共资源。直接上图:
4.细化与扩展
其实在第三步之后整个项目结构已经算是比较完整了,不过随着项目的不断扩大,模块仍然还是需要不断细分。这里说一下整个项目结构的一种规划思路。
在上述的项目结构中,严格来说只有三层:系统层、业务逻辑和app层。
其中app层是相对简单的,只要包含应用启动和初始化的一些额外操作和逻辑。而业务层包含了所有划分出来的子功能模块,为了方便项目结构的显示方便,我们可以把这些模块放在统一的文件夹下
这里需要注意的是放在文件夹下的module在引用时要注意带上相对路径。比如这里的moduleUser在引用时就要从":moduleUser"
变成":moduleCore:moduleUser"
,多级以次类推。
同样,对中间层我们也可以采用类似的方式,因为中间层不仅会包含一些我们自定义的通用实体类等文件,还有可能会有我们常用的二次封装过的三方库和开源库。这些库有些本身就是一个module需要我们引入,有些则是我们经过二次封装的module。这些module同样不适合放在系统层,所以也可以归到公共层里,例如在我的项目里就有支付宝SDK,高德地图等通用moudle
最后在说一下系统层,虽然说这一层叫系统层,但是各个module之间实际上并不一定是平级关系的。比如在我的项目中我引入了greenDAO数据库框架。这个我作为一个单独的数据库模块放在了系统层,但是在层级上是最底层,被moduleBase引用。
最后,附上完整的设计思路和项目结构:
这里需要说明一下各个模块之间的引用关系。建议各个模块在引用的时候都采用implementation的方式全部引用。例如app模块需要在gradle配置文件中引入所有需要用到的模块,这样可以不用考虑api方式产生的子模块继承引入的问题。例如app模块引入了moduleBill模块,而moduleBill引入了muduleA模块,那么app还需不需要引入这个模块呢?使用implementation的方式虽然繁琐了一点,但是也最大程度的保证了项目结构的清晰。
到这里,一个基本的组件化项目结构就搭建完成了。这一部分主要是介绍了模块划分的逻辑和依据,偏向思想。实际开发过程中,因为各个module之间的引用关系还有很多的坑,这一部分我会在下一篇文章详细说明。这里就不在赘述。
转自:https://www.jianshu.com/p/748bf621a9a0