背景
随着业务不断的迭代发展,内容详情页的业务模式正变得越来越复杂。诸如九空格式短图文、顶部翻页横划式短图文、视频、Stroy播放及长图文等各种玩法层出不穷,内容详情页也经历了纯Native开发、纯Hybrid开发及目前的长图文Hybrid开发、短图文及视频采用Native开发的模式。为了应对灵活多变的产品形态,原来单控制器、单ViewModel管理所有页面功能的架构模式显然是不合适的,因此我们对原有的架构模式进行了大尺度的重构。
痛点
- 单控制器模式痛点
控制器ViewController,数据源ViewModel无比臃肿
将不同形态下的功能,强行堆在一个控制器或者一个ViewModel中,代码逻辑显得异常凌乱
代码的可读性,可维护性很弱
- 评论模块痛点
严重耦合业务,强依赖ClientItem
评论Cell没有高度缓存机制
多个评论接口,没有做合并处理
先介绍下重构后的收益,再分析重构中的指导思想及设计方案。
收益
不同形态基于一个Base 控制器,高效地收敛了共同属性,处理了共同的业务逻辑
不同形态内容采用独立的子控制器承载,有效地隔离了差异性,每个控制器可以更专注于自身独有的逻辑功能
评论模块下沉,独立于业务,复用性很强,一行代码即可实现在feed中发表评论,充分地解放了生产力
评论Cell高度缓存,让页面滑动如丝般顺滑
代码可读性、可维护性更强,分析问题,解决问题的效率得到了极大地提升
原则
对外接口不变
由于项目中已经有大量的入口可以直达详情页,同时,还有部分入口是通过Schema跳转,从稳定性和拓展性的角度考虑,我们在重构时必须保证对外接口的不变。单一职责
大到一个类,小到一个方法,我们都要保证职责的单一,绝不能因为一时的不冷静,将所有的逻辑堆在一起,这样的代码后续是无法维护的。
方案
内容详情页一般都由内容和评论两大部分组成,下文将从内容和评论两个业务类型角度出发,分别阐述设计思想及部分实现细节。
内容
-
工厂模式
通过一个工厂来动态生成控制器,根据不同的itemType 生成不同的控制器。 -
MVVM + 继承 + 组合模式
通过继承加组合的模式,细粒度地分拆了模块功能,同时也高效地实现了代码复用。
采用MVVM模式,每个ViewController绑定一个ViewModel,ViewModel控制视图的展示,达到数据驱动视图的目的。
-
控制器viewController
如上图,控制器采用了继承的模式,不同的业务分别由不同的子控制器承载
@dynamic
为了实现各个Child ViewController持有一个与之对应的Child ViewModel, 在Base ViewController中持有Base ViewModel, 同时,利用@dynamic特性,控制在各个Child ViewController中不生成viewModel成员变量,直接复用Base ViewController中生成的View Model。视图结构
Base ViewController只提供基础组件,比如tableview、emptyview,将组件的组装、布局留给Child ViewController,这很大程度上兼顾了复用性与灵活性。
ViewModel
ViewModel部分采用了继承加组合的模式,有一个Base ViewModel,然后根据不同的业务分别创建Child ViewModel。ViewModel提供了数据源、评论及操作(点赞、关注等)等功能,将评论、操作等功能分拆出去,采用单独的ViewModel管理,然后通过组合的方式,将评论和操作的功能装载到Base ViewModel中。
-
评论
- 高度缓存
每一行评论作为UITableView的一个Cell,UITableView在布局的时候,会多次询问每一行Cell的高度,而且动态计算Cell的高度是较为耗时的操作,因此将高度缓存可以有效提升页面的性能。 - 评论组件化
我们认为评论应该是比较基础的功能,不应该耦合业务代码,因此将评论下沉,与业务解耦,可以方便地将评论应用到更多的业务场景中。
展望
一个好的架构,能很大程度上提升开发生产力,有助于后续的扩展,维护。但是随着业务的蓬勃发展,原有架构也一定会受到挑战,因此,要有一颗拥抱变化的心,不停地学习,不停地重构,让代码越写越精,越写越壮。