读过很多设计模式,看过很多开源代码,却依然被产品整的死去活来. 过完春节,开年空的这几天终于可以歇一会,写写博客.
现在我们从实战出发,聊一聊类似朋友圈这样的页面应该如果去设计,开发.(这里就先抛砖引玉了)
1:确认完需求拿到视觉稿
此时脑子会有无数的设计闪过,如何做每一个层的规划.最后定下来这样的一个流程.
View: 只是view 用于显示数据 和 事件触发
ViewManager: 1: 他包含 DataSource 用于提供给ViewManager 的数据(ViewModel) , ViewManager再把数据(ViewModel)赋给View, 让View进行渲染 2:接收View触发的事件,提供给Handler,让Handler进行处理 3:ViewManager 可以是vc , 也可以是NSObject, 如果数据和页面足够简单View本身也可以是一个 ViewManager 4:ViewManager可以包含其他ViewManager
Handler: 1:只是处理 View所触发的事件 他可以是页面跳转, 也可以是触发DataSource的数据更新 2:Handler也可以包含其他Handler
DataSource: 这个数据源 其实是和业务相关的, 把最终处理完成的后的ViewModel 返回给ViewManager 他会给外部提供简单的接口给Handler 使用, (插入,合并,排序等操作都是在DataSource里面完成)
Manager: 这个只是基础的对外提供原始数据的对象 , 你可以把他看成一个网络请求的Manager 或者本地数据 返回的只是最原始的model(单纯描述数据) 不和具体页面有关系 可能这个叫做Service 更好点图已经画了懒得改了.....
Model:基础的数据模型 不和上层业务相关
2:开始干活
那么根据这样的准则我就先拿动态流 举例吧.
看到这样的页面的我们首先会想到的是万能的tableView
我们先进行结构的划分
先把他定为 2大块 TableView 作为一个 ViewManager 上面的信息页面作为一个ViewManager
先来说下TableView 的ViewManager 这里我们为了方便就直接把 VC作为TableView的ViewManager.当然为了让VC更加干净也可以 TableView开一个TableViewManager 给VC 让VC持有这个TableViewManager. 不过这样就要你需要让VC暴露TableViewManager需要的一些属性和方法(为了偷懒).
遵循ViewManager的准则
DataSource 提供处理完的数据给 vc vc给予View (也就是上面的Cell) View(也就是Cell)事件分发给vc 让vc交给handler处理
下面看下代码
DataSource:
这里 DataSource就是这样只对外提供了一个获取当前数据(也就是一个数组 里面包含了 广告 ,动态 等数据的ViewModel)
VC:
图 6: vc持有 Handler 和 DataSource
图 7: vc从DataSource 获取当前的数据
图 8: vc 把数据给 tableView
图 9: View 把事件提交给 vc 让vc 交给 Handler去处理
(这里有个event. 有些人可能喜欢view的回调用delegate 这样参数可以自解释,不过当要增加一个参数就要改很多地方. 有些人可以喜欢用block方便,参数也可以随意增加. event 无非所有传递都是通过model不用添加额外的方法(懒), 好处不用到处都是delegate 和block回调, 坏处不能自解释,要写注释. 个人喜好这种大家可以按自己熟悉的来我这里先用event.)
这样一整套上层的流程就算定完了.接下来干正事,就是画View(毕竟大量时间都是UI工程师).
3:细分TableView的cell
对于看起来是一整块的cell来说,数据源只是一个ViewModel,实际上是需要拆分层许许多多的小cell的,无非是关乎性能和关乎更好的维护,后续添加和删除内容更容易(比如后续要接各种广告, 加视频 ,小视频这种需求).这里先这么简单的来拆分一下看到的1,2,3,4,5这么5块(虽然实际上更多 ,不过都是重复的劳动).
我们提出3号这个cell来讲解下. 这是一个有点赞,评论,分享.3个功能的一个cell.
之前说过cell他也不过是一个View,既然是View那他只有2个职责 1:负责渲染 2:触发事件.
以前我们总是碰到model你都没定义好怎么进行View开发呢,写UI的人留出位置等model,然后去处理model去了. 所以这里我们已经理解了交互,UI完全是可以和数据层并行开发的.比如这个点赞,评论,分享的View,对它来说它需要知道什么? 它只需要知道我这个按钮到底是不是点赞的状态.那么写这个点赞View的人只需要对外提供一个Protocol 类似这样
这个View只要知道 ,是否点赞的状态的就可以,所有渲染都是基于这个Protocol, 这个Protocol交给ViewModel去实现. 而View并不关心到底是什么model,完全可以多人并行开发最后让ViewModel去实现这个Protocol,然后所有工作都完成了.
(这里到底是只用一个Protocol包含所有View, 还是每个View一个Protocol, 这个和领导争论了很久. 如果是每个View一个Protocol,这样就看起来分的太细, 让后续维护的人看起来很麻烦又不好理解. 但是好处是, 比如这个点赞评论分享的View,详情页面用到,那么就让详情页的ViewModel去实现这个数据,可以复用. 可是也有一个问题,如果视觉设计的2边的不一致,那还是要写2套. 如果是一个Protocol都包含所有View需要的,那么对于单个View来说又看上去太冗余, 职责不单一. 又有人问既然是一个Protocol为什么不直接用ViewModel,这是因为ViewModel会有一些和View显示不相关的方法比如插入,删除等,这些操作是没必要暴露给View. View就只有2件事情 显示,触发,越简单越好,不关心数据,后续即使数据变更也没关系.不用影响到View里面的修改,无非是底层和ViewModel是事情了. 如果大家有更好的思路可以说明下)
所以关于一个View的渲染和触发事件的结构是这样的
按照这样的结构我们来看 3号这个cell 关于一个点赞事件的 显示 触发 更新的流程
图 13 点赞的按钮的 的显示是 更具自己 提供的Protocol
图 14 触发点赞的请求
图 15 传递给了可以处理的Handler 进行处理
图 16 Handler选择调用 DataSource 点赞的方法 , 最后DataSource把更新完后的数据扔给ViewManager 说数据更新了 ViewManager再把新的数据给予View
关于DataSource里面的点赞怎么实现的, 是否要加离线点赞,这些都是后话. 这些都是扔给底层的Manager去处理,这个底层Manager后面的文章会细讲.
就这样一个View的从显示到触发事件的流程都跑完, 其他也都依葫芦画瓢(体力活).
4:上层流程的总结
开发中需要注意的点
1: 关于Handler的拆分 在这里主要把原本在VC处理的业务交给了 Handler .如何让单个Handler不臃肿,比如现在我们的App只把 键盘事件 和 分享 公用的单独作为一个Handler分了出去. 之后随着业务的增加需要思考.
2: 如何细分 View, View分的细开发起来麻烦, View分的大后续维护扩展会很麻烦. 这些都需要根据大家业务本身进行取舍.
3:有时候一个复杂页面有时候会涉及很多结构, 老生常谈如MVC,MVP. 或者MVVM,VIPER. 或者有着你自己思想的结构. 这些也需要看你具体业务进行选择, 比如你的新增业务只有一个Button按下去的事件做跳转,这还需要什么结构.如果后续多了再进行结构的调整.
4:写了这么多, 最后吐槽下,没有什么万能的设计模式, 只有漫漫长夜的加班中的进行代码结构的优化.