背景
目前商业SDK中的点击事件,会根据不同的「事件类型」+「业务类型」,去执行不同的路由跳转逻辑,然而不同的跳转事件内部又有着很复杂的跳转逻辑,
痛点
- 不同的跳转逻辑之间存在耦合
例如,在deeplink的跳转逻辑之中有其他跳转逻辑,如果dp失败后会走normal的路由跳转;或者有些业务有deeplink链接的时候跳转dpplink,没有dp的时候会跳转默认的链接。 - 代码可读性差,维护成本高
在某一个click事件当中,由于产品特性,可能会包含多个跳转逻辑,例如:跳转视频、跳转网页等等。 - 排查问题的难度增加
基于以上现状,在排查跳转问题的时候,需要花费较长的时间去梳理代码。
现状流程图
可以从上图看出,跳转逻辑相互关联,对于代码流程处理异常艰难。
优化想法
-
由于每一个卡片跳转都有一定的顺序和流程。我们需要整体先后顺序。
-
拉产品沟通,将跳转的先后顺序以及 成功的条件进行沟通。
沟通后流程如图:
方案
初步想的方案是,根据跳转的页面的优先级,做一个类似链表的结构体,然后链表的每个子元素都是一个页面跳转流程。 根据「页面跳转的成功」条件去进行判断,如果某个子元素跳转成功,那么returen掉,如果失败,那么继续走到下一个链表的子元素。以此类推,最终走向兜底逻辑。
原理其实很简单,就是一个链式表达式,哪个成功那么就跳转哪个,后边的流程不执行。
调用方式如下:
//构建各个路由跳转的元素成链条 var routers: [ChainedRouter] = [RouterA(), RouterB(), RouterC(), RouterD()...]// 通过方法调用,并传入对应的字段routers.chain()?.route(with: dataA, dataB: dataB, other: otherMessage)
优化架构图:
优化流程图
调用方式参考
//构建各个路由跳转的元素成链条 var routers: [ChainedRouter] = [RouterA(), RouterB(), RouterC(), RouterD()...]// 通过方法调用,并传入对应的字段routers.chain()?.route(with: dataA, dataB: dataB, other: otherMessage)
核心代码分享
protocol HmgRouter: AnyObject {// 只需看当前响应者是否响应,不需要处理责任链传递func tryToRoute(with model: NSObject?, context: [String: Any]?, completionHandler: @escaping ((Bool) -> Void))
}protocol HMGChainedRouter: HmgRouter, HmgRouterLifeCycle {var next: HMGChainedRouter? { get set }
}protocol HmgRouterLifeCycle: AnyObject {var success: (() -> Void)? { get set }var failed: (() -> Void)? { get set }func lifeCycleCallBack(_ result: Bool)
}extension HmgRouterLifeCycle {func lifeCycleCallBack(_ result: Bool) {if result {if let success = success {success()}} else {if let failed = failed {failed()}}}
}extension HMGChainedRouter {func route(with model: NSObject?, context: [String: Any]?, completionHandler: ((Bool) -> Void)?) {tryToRoute(with: model, context: context, viewAction: viewAction) { res inif !res, let next = self.next {next.route(with: model, context: context, viewAction: viewAction, completionHandler: completionHandler)}completionHandler?(res)}}
}class HmgRouterBuilder {private var top: HMGChainedRouter?private var tail: HMGChainedRouter?func add(_ router: HMGChainedRouter) -> Self {if top == nil {top = routertail = router} else {tail?.next = routertail = router}return self}func clean() -> Self {top = niltail = nilreturn self}func build() -> HMGChainedRouter? {return top}
}extension Array where Element == HMGChainedRouter {func chain() -> Element? {let a: (HMGChainedRouter?, HMGChainedRouter?) = (nil, nil)return reduce(a) { (res, current) inlet (top, tail) = resguard let h = top else {return (current, current)}tail?.next = currentreturn (h, current)}.0}
}
思考
本文中的实现方式其实就是一种责任链的实现。 我的另一篇文章详细介绍了一个责任链模式的使用场景以及常规的实现方式。 责任链模式是代码中经常要用到的。责任链其实就是某个业务场景下每个处理理单元负责一部分任务,形成一个连续处理的链条,直到任务被处理或无人处理。这种模式使得代码结构清晰,易于扩展。
附上责任链文章:https://blog.csdn.net/liyunxiangrxm/article/details/130827650