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

相关推荐
颜颜yan_2 小时前
【HarmonyOS5】UIAbility组件生命周期详解:从创建到销毁的全景解析
架构·harmonyos·鸿蒙·鸿蒙系统
打码人的日常分享5 小时前
智慧城市建设方案
大数据·架构·智慧城市·制造
鲁班大叔_0076 小时前
使用扣子与Dify的业务风险
架构·产品
hello早上好6 小时前
Spring不同类型的ApplicationContext的创建方式
java·后端·架构
Python智慧行囊7 小时前
Python 中 Django 中间件:原理、方法与实战应用
python·中间件·架构·django·开发
HyggeBest7 小时前
Mysql的数据存储结构
后端·架构
冰橙子id8 小时前
centos7编译安装LNMP架构
mysql·nginx·架构·centos·php
喵叔哟8 小时前
25.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--用户服务接口
微服务·架构·.net
WindrunnerMax13 小时前
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
前端·架构·github
hstar952713 小时前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc