商业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

相关推荐
麦聪聊数据3 分钟前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
程序员侠客行1 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
bobuddy2 小时前
射频收发机架构简介
架构·射频工程
桌面运维家2 小时前
vDisk考试环境IO性能怎么优化?VOI架构实战指南
架构
一个骇客4 小时前
让你的数据成为“操作日志”和“模型饲料”:事件溯源、CQRS与DataFrame漫谈
架构
鹏北海-RemHusband5 小时前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构
2的n次方_7 小时前
Runtime 内存管理深化:推理批处理下的内存复用与生命周期精细控制
c语言·网络·架构
前端市界8 小时前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github
文艺理科生8 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
C澒8 小时前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构