商业iOS端路由架构演进

背景

目前商业SDK中的点击事件,会根据不同的「事件类型」+「业务类型」,去执行不同的路由跳转逻辑,然而不同的跳转事件内部又有着很复杂的跳转逻辑,

痛点

  1. 不同的跳转逻辑之间存在耦合
    例如,在deeplink的跳转逻辑之中有其他跳转逻辑,如果dp失败后会走normal的路由跳转;或者有些业务有deeplink链接的时候跳转dpplink,没有dp的时候会跳转默认的链接。
  2. 代码可读性差,维护成本高
    在某一个click事件当中,由于产品特性,可能会包含多个跳转逻辑,例如:跳转视频、跳转网页等等。
  3. 排查问题的难度增加

基于以上现状,在排查跳转问题的时候,需要花费较长的时间去梳理代码。

现状流程图

可以从上图看出,跳转逻辑相互关联,对于代码流程处理异常艰难。

优化想法

  1. 由于每一个卡片跳转都有一定的顺序和流程。我们需要整体先后顺序。

  2. 拉产品沟通,将跳转的先后顺序以及 成功的条件进行沟通。

沟通后流程如图:

方案

初步想的方案是,根据跳转的页面的优先级,做一个类似链表的结构体,然后链表的每个子元素都是一个页面跳转流程。 根据「页面跳转的成功」条件去进行判断,如果某个子元素跳转成功,那么returen掉,如果失败,那么继续走到下一个链表的子元素。以此类推,最终走向兜底逻辑。

原理其实很简单,就是一个链式表达式,哪个成功那么就跳转哪个,后边的流程不执行。

调用方式如下:

objectivec 复制代码
//构建各个路由跳转的元素成链条     

var routers: [ChainedRouter] = [RouterA(), RouterB(), RouterC(), RouterD()...]

// 通过方法调用,并传入对应的字段

routers.chain()?.route(with: dataA, dataB: dataB, other: otherMessage)

优化架构图:

优化流程图

调用方式参考

objectivec 复制代码
//构建各个路由跳转的元素成链条     

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 in
            if !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 = router
            tail = router
        } else {
            tail?.next = router
            tail = router
        }
        return self
    }
 
    func clean() -> Self {
        top = nil
        tail = nil
        return 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) in
            let (top, tail) = res
            guard let h = top else {
                return (current, current)
            }
            tail?.next = current
            return (h, current)
        }.0
    }
}

思考

本文中的实现方式其实就是一种责任链的实现。 我的另一篇文章详细介绍了一个责任链模式的使用场景以及常规的实现方式。 责任链模式是代码中经常要用到的。责任链其实就是某个业务场景下每个处理理单元负责一部分任务,形成一个连续处理的链条,直到任务被处理或无人处理。这种模式使得代码结构清晰,易于扩展。

附上责任链文章:https://blog.csdn.net/liyunxiangrxm/article/details/130827650

相关推荐
Java 码农39 分钟前
mysql8.4.6 LTS 主从架构搭建
mysql·adb·架构
麦麦大数据1 小时前
F038 vue+flask 微博舆情热搜情感分析大数据分析系统|前后端分离架构
vue.js·架构·flask·情感分析·微博·舆情分析
sorryhc3 小时前
Webpack中的插件流程是怎么实现的?
前端·webpack·架构
gfdgd xi4 小时前
GXDE For deepin 25:deepin25 能用上 GXDE 了!
linux·运维·python·ubuntu·架构·bug·deepin
Yeats_Liao7 小时前
Go Web 编程快速入门 12 - 微服务架构:服务发现、负载均衡与分布式系统
前端·后端·架构·golang
开发者如是说7 小时前
我用 Compose 写了一个 i18n 多语言管理工具
前端·后端·架构
敲敲了个代码8 小时前
为什么 Electron 项目推荐使用 Monorepo 架构 [特殊字符][特殊字符][特殊字符]
前端·javascript·学习·架构·electron·github
zhilin_tang9 小时前
在rk3568上架构纯c语言json脚本+webrtc服务音频设备播放设备程序
c语言·架构·json
文军的烹饪实验室9 小时前
CPU 架构(CPU Architecture)
架构·cpu
getapi9 小时前
一个完整的 AWS 无服务器架构教程
架构·serverless·aws