

优雅移除模块间耦合-讲稿 - 小专栏
source link: https://xiaozhuanlan.com/topic/9843071526
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.


这篇文章是我在 2017 北京【droidcon 大会】技术分享时所讲内容的文字版本,修改删减了演讲时的冗余言语。
仅发布在【小专栏】,希望能给买不到票参加大会的朋友带来帮助。


首先自我介绍一下:我叫张涛,目前是饿了么移动技术部。可能有些朋友认识我,我有一个博客叫【开源实验室】应该或多或少都有听过一些。其他一些虚的东西就不说了,接下来进入今天的主题。

今天我们讲的主题是基于项目模块化来说的,模块化是什么大家肯定都是知道了的,这里问一下大家,有多少人在此之前有做过模块化的,举个手我看一下;了解过听说过模块化的呢?这次比较多。
我们说,做模块化其实跟项目重构很像,都是从这几个点来做的,只是侧重点不同。分别是:删除、组织、降级、解耦。那么这四点是什么意思呢,那么接下来跟大家分享一下我是如何理解这四大块的:

删除:删除不必要的文件,尽可能减小工程体积。这里有一组数据,是我统计我们饿了么的一款 APP 在模块化前后一些文件的数量。
可以看到,.java
文件从1677个减少到了1543个。其实这不是重点,重点是下面的drawable
,这里drawable
只包含图片、和xml
布局,当经过模块化重构后文件数从 693 减少到 538 个。图片资源减少接近 200 个,apk 的大小也会随之降低。

而组织呢,指的是:按照有意义的标准将代码分组。这其实也是java
的包所存在的目的之一。
但是随着项目的不断迭代,需求很紧的情况下是很难有时间去真正规范的将类分组的。看到图中,我们之前的结构很乱,就是因为项目快速迭代和人员更替的过程中,不免会有这样的现象。所以这也是模块化重构时所作的一件大事。

接下来就是我们经常说的内聚和耦合了,但是呢内聚不是我们想象的那样的。我不知道大家有没有看过RecyclerView
的源码,RecyclerView
总共有五个主要的类,分别是:LayoutManager
、Adapter
、ViewHolder
、ItemAnimator
、ItemDecoration
但是都写在了一个类里面,后来我在某个社交平台上看到有人说这叫高内聚,非常的搞笑。
再看回我们项目中的这个例子,降级。我们之前有一个类叫:Navigator
,它是负责几乎所有Activity
直接跳转的。就是我们会把所有的startActivity()
的跳转放到这个类里面去写。之前少的时候还好,结果等我看到这个类的时候,这个类已经有 200 多个方法了,全是Activity
跳转的方法,其中还有重复的,就是很早之前有人写了一个跳到某个界面,结果之后来了个人,他不知道又写一个。
而我们在做模块化重构时的做法就是,首先观察自己的项目,这是重构很重要的一步,就是要结合自身。把这个类拆分成了三大部分,我们有两块业务是会频繁跳转的但这两个业务跳转的页面又都是在自身的模块内,分别是用户模块和商户模块。因此我们将这两个模块中分别建立两个用于模块自己内部的跳转叫UserNavigator
和ShopNavigator
,而模块间的跳转或一些小模块内部的则使用Router
去做,我们自己定义了一个路由库,其实实现跟现在开源的区别不大。

最后解耦,也是今天的重点,如何优雅移除模块间的耦合。
到目前为止,我们已经能够做到让所有不包含业务状态接口的模块的增删,不需要改动任何一行代码。具体到一个示例就是这样:

其本质就是一个模块就是一个功能,你想要让你的 apk 具备这个功能,就添加这个模块一起编译就可以了。这才是我们说的真正的组件化,模块之间零耦合,增减模块零改动。
例如图中:debug
这个模块,肯定不会用在正式的生产环境;而相反的tinker
这个模块,热补丁肯定也不会用于调试阶段。所以我在开发时就可以不使用这个模块相关的代码。
另外再举个使用的例子:我有一个订单模块,订单模块需要播放铃声,比如大家在饭店经常听到“您有新的饿了么订单,请及时处理”。但我在开发订单模块的时候,如果我已经确定铃声播放是没有问题的,那我可以选择开发阶段不打铃声的包,直到发布到线上了再去加上铃声的包。那我没有添加这个铃声模块的时候,我就默认不具备播放铃声的功能,但完全不影响其他的订单模块的业务功能,而这个铃声模块的增删,是不需要修改任何代码的。
听到这里相信大家都很好奇这是怎么实现的。接下来就跟大家讲讲内部的原理。

所有的核心功能都来自我们自己写的一个库:IronBank
。取《自冰与火之歌》中的【铁金库】,叫铁金库不容拖欠。
铁金库的内部实现,其实是使用了 APT 注解处理器,去在编译时解析注解生成一个类,让这个类去生成跨模块的对象。铁金库使用了与 SOA 设计思路类似的方式:将模块之间的主动依赖倒置,变为功能的提供与使用。
那什么是 SOA 的设计思路呢,我们看到一张我画的漫画图:SOA 是一种面向服务的架构模型。

例如图上左边有一个对外提供媒体功能的服务提供者,他告知IronBank
我提供媒体服务:“嘿,老铁,我这有个媒体服务,你那边有谁要用的时候可以用我的。”
到了另一边,如果此刻有模块说是,我需要媒体服务:“老铁,你那有没有媒体服务,我这边需要播一个铃声啊!”。
“有的,给你。” IronBank
就会将之前服务提供者提供给他的媒体对象交给服务使用者。

Recommend
-
174
2017年如何在移动端优雅的使用flex号外号外:专注于移动端的fullPage.js来啦!!!快点我查看做过移动端的同学都...
-
73
小小的IP,大大的耦合,你痛过吗? Original...
-
117
服务化了,没想到耦合更加严重? Original...
-
70
背景最近在项目中遇到这样一个场景,在直播间的主播端有个功能区,里面是一些插件,这些插件之间在业务上存在互斥关系,也就是A处于开启状态时,B、C、D、E甚至是甲乙丙丁都不能打开。随着这块业务的增多,由于没有及时重构,导致互斥逻辑写的很是让人抓狂。
-
75
-
80
2018年11月21晚19:30-20:30。 《壹课Online》本次特别邀请到了一位重量级嘉宾,浪潮思科网络科技有限公司高级SDN架构师——刘照德先生,来给大家进行《浅谈数据中心SDN解耦合》的分享。...
-
52
写在前面 在 一名一线开发对于App架构和组件化的思考 文章中,我们主要站在了软件工程的角度上,分析了做App架构和组件化时该如何下手,其中也介绍了路由和服...
-
11
Android 模块化平台设计-讲稿 2018-04-22 By 张涛 | 本文已被访问9116次 版权声明:本...
-
11
《ifLab 和你的故事》- 第一份实习/工作(讲稿)又到了新的一期《ifLab 和你的故事》电台节目主题「第一份实习/工作」。这个主题是大师兄在今年暑假之前想到的,我觉得这个主题非常好,最近社团同学们陆陆续续的离开了学校,还真的没有文章去讲述过这...
-
8
[讲稿] CGDC2009 演讲:游戏峡谷地图自动生成 2009年在上海 CGDC的演讲稿《游戏地图自动生成》,该算法主要用来生成山地峡谷地图。 266 total views, 1 view toda...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK