0%

从一次架构重构浅谈客户端业务架构技巧

1 背景

最近半年做了一次大的业务架构重构,总体涉及 2w 多行代码,整个弄完以后个人对客户端架构侧的基本概念又有了一些新的理解。

2 问题

模块功能大概是类似音视频上下滑列表,整体有两大块,上下滑容器详情页。页面结构如上图(示意图)所示。

fgwGFS.md.png

原始的框架核心类如上图所示:

  1. 上下滑容器类,各种跟上下滑相关的逻辑都放在这个视图控制器中,业务方继承上下滑容器类,则他拥有上下滑能力,并且可以通过该业务子类重写父类里面的方法,来达到业务逻辑的定制;
  2. 详情页接口类,是一个纯接口。业务方通过实现该接口里面的各种方法把详情页融入上下滑框架;
  3. 接口回调是一个代理接口类,主要用于返回详情页事件,让容器感知各种详情页事件,执行对应操作。

经过长期业务迭代,发现上下滑容器类耦合严重,究其原因主要是两方面:

  1. 附加功能和基本功能堆叠,即上下滑容器职责不单一,整个代码接近 2k 行,包含滑动,刷新,触底,网络监控,快速起播,缓存等等许多逻辑。这直接导致我们添加、删除、修改上面的业务逻辑非常不方便。
  2. 上下滑容器承载了详情页的业务逻辑,即上下滑容器里面直接关联了详情页,详情页和上下滑容器通过详情页回调通信。这样使得上下滑容器里面的业务层和功能层耦合了,因为上下滑容器既要实现功能层的滑动框架等基本功能,也需要关注详情页的个性化事件进行对应处理。

3 附加功能和基本功能堆叠的解法——模块、插件与服务

3.1 经典做法——分类

针对附加功能和基本功能堆叠这个问题,我们有一个经典做法——分类。把上下滑容器页按照功能拆分为主类和分类。就我们这个上下文来说,上下滑承接这种逻辑可能在主类里面,其他诸如缓存逻辑、预加载逻辑、刷新控制逻辑等都可以独立为分类。这种做法的好处就是简单清晰。不过此方案至少存在两个缺陷:

  1. 如果业务方想删除某个附加逻辑,则仍然需要继承整个页面容器后覆盖一个个分类函数,后续调试维护不是很方便;
  2. 如果业务方想新增独立的附加逻辑,首先是需要建立一个业务侧分类,然后需要在主类里面导入这个新的业务分类,并在合适的时机调用这些分类方法。这里就存在主类对业务方分类的反向依赖。

    3.2 聚合关联业务逻辑——模块化

经典方案的缺陷本质是分类依赖了主类的时机和数据。比如,就预加载分类来说,主类在视图生命周期和上下滑切换这两个时机需要调用预加载分类的预加载方法。针对这个问题,我们可以使用观察者模式,即把主类当做主题,抛出时机和数据,分类作为观察者接受时机和数据执行动作,以此解耦。更进一步,观察者可以不用是一个分类,只要是一个简单的对象类就可以。我们暂且把这个类称为模块类,它聚合了一块独立的业务逻辑,感知容器类的事件和数据执行具体的动作。

fgw1df.png

3.3 标准化输入输出——插件化

标准化容器类的数据和事件,比如提供统一的生命周期,上下滑,网络,展示等事件。同时,附加模块对外提供统一的 API 接口。再加上附加模块本身就是观察者,天然可插拔。这样一个模块就相当于上下滑主题的插件。

fgw3o8.png

3.4 依赖接口不依赖实现——服务化

针对某些场景,业务方需要整体重写某个插件,比如要重写预加载插件。如果我们在框架的其他类里面直接依赖了具体的预加载插件类,则这件事变得很艰难。比较优雅的做法是预加载抽出一个接口,插件类实现该接口。其他地方通过服务发现访问插件接口而不是直接调用某个具体的插件类。同时插件接口通常比较简单,方便下沉分层。这个思路其实是借鉴组件分层,组件接口下沉,接口库和实现库分层。

fgwleP.png

4 容器承载详情页业务逻辑的解法——功能层与业务层分离

fgwJJg.md.png

4.1 问题的分析

另外一个问题是上下滑容器承载了独特详情页的逻辑,即原始的框架是上下滑容器里面直接关联了详情页,详情页通过回调告知上下滑容器自己发生的事件,上下滑容器收到对应事件后执行调用。这样使得上下滑容器里面的业务层和功能层耦合了,因为上下滑容器既要实现功能层的滑动框架等基本功能,也需要关注详情页的个性化事件进行对应处理。

4.2 来自 IGList 的启发——功能层和业务层分离

针对这个问题,我们可以直接借鉴 IGList 的思想,IGList 中每个详情页被 SectionController 管理起来了,框架只感知 SectionController,不感知详情页。因此,新上下滑容器不是直接访问详情页,而是中间有一层业务层 ViewItem。ViewItem 组合一个详情页并且接受对应的事件回调。接到事件回调后,可以调用功能层的各种插件服务。这样使得上下滑容器变成一个纯粹的功能层,不再感知具体业务。综上,上下滑容器变成纯粹的功能类,业务这部分由 ViewItem 承接起来了,因为是 ViewItem 感知了详情页事件并进行逻辑判断后调用上下滑容器的基础功能去执行。具体如上图所示。

5 总结

本次记录了一次业务架构重构的技术侧构思,原来对一些架构名词的认知还是停留在纸面,经过此次实践理解更加深刻了。