OSMBonusPack源码剖析:RoadManager模板方法模式与4种路由服务的可扩展设计 📅 发布时间:2026/8/24 11:31:25 👁 浏览次数: OSMBonusPack源码剖析RoadManager模板方法模式与4种路由服务的可扩展设计【免费下载链接】osmbonuspackA third-party library of (very) useful additional objects for osmdroid项目地址: https://gitcode.com/gh_mirrors/os/osmbonuspackOSMBonusPack 是 osmdroidAndroid 平台 OpenStreetMap 地图库的官方扩展组件库其中路由Routing模块通过RoadManager 模板方法模式将 OSRM、GraphHopper、MapQuest、Google 四种路由服务统一封装上层代码只需面向RoadManager抽象类编程即可随时替换底层路由引擎且任何服务出错时都能优雅降级为直线路线。本文带你剖析这套可扩展设计的实现细节。 路由模块全景一个包搞定四种引擎所有路由代码集中在routing/包下共 8 个类抽象基类RoadManager.java数据模型Road.java、RoadLeg.java、RoadNode.java四个服务实现OSRMRoadManager.java、GraphHopperRoadManager.java、MapQuestRoadManager.java、GoogleRoadManager.java引擎返回格式备选路线API Key特色OSRMJSON✅免 Key免费开源自托管支持驾车/骑行/步行三种模式GraphHopperJSON✅可选需要可选海拔数据车辆类型参数MapQuestJSON❌ 仅一条需要Guidance API v2link/node 结构GoogleXML✅代码内置服务SAX 流式解析节省内存️ 模板方法模式基类定骨架子类填血肉两个抽象方法就是模板RoadManager是抽象类核心契约只有两个方法见 RoadManager.java#L29-L38getRoad(waypoints)返回单条路线取最短getRoads(waypoints)返回路线数组下标 0 是耗时最短的其余为备选路线每个子类都遵守同一实现套路getRoads(waypoints)内部调用私有重载getRoads(waypoints, true/false)是否取备选getRoad则取数组第一个元素。以 OSRM 为例OSRMRoadManager.java#L281-L288Override public Road[] getRoads(ArrayListGeoPoint waypoints) { return getRoads(waypoints, true); // 要备选路线 } Override public Road getRoad(ArrayListGeoPoint waypoints) { Road[] roads getRoads(waypoints, false); return roads[0]; }这就是模板方法模式的精髓算法骨架请求→解析→兜底固定URL 拼接与响应解析交给子类。三个共享工具消灭重复代码基类把各服务通用的能力下沉子类直接复用透传请求参数addRequestOption()把任意参数如 GraphHopper 的vehiclebike、MapQuest 的routeTypebicycle拼到 URL 尾部见 RoadManager.java#L50-L52坐标格式化geoPointAsString()输出lat,lonOSRM/Google 之外的服务用geoPointAsLonLatString()输出lon,latOSRM 专用见 RoadManager.java#L57-L68。10 位小数保证精度注意不同服务的坐标顺序差异正是靠这一对方法抹平的一键绘制路线静态方法buildRoadOverlay(road)直接把Road转成地图上可点击的半透明蓝色 Polyline默认色0x800000FF、宽 5 像素见 RoadManager.java#L76-L93 四种引擎的实现差异OSRMJSON 解析 机动指令映射OSRM 默认请求官方演示服务可setService()换成自托管实例getUrl()用分号连接lon,lat坐标序列见 OSRMRoadManager.java#L138-L150。解析过程OSRMRoadManager.java#L191-L279有两个亮点路线几何用 PolylineEncoder 解码 Google 编码折线体积远小于原始坐标数组静态MANEUVERS映射表OSRMRoadManager.java#L43-L84把 OSRM 的turn-left、roundabout-2等文本指令转成 MapQuest 风格的数字编码再查本地化字符串资源生成前方左转沿 XX 路行驶这样的播报文案GoogleSAX 流式解析 XMLGoogle 接口返回 XMLGoogleRoadManager用SAXParser配一个事件处理器逐标签解析GoogleRoadManager.java#L107-L123而非把整个 XML 读进内存——对长路线更省内存。内部类GoogleDirectionsHandler用一组 boolean 状态机标志isLeg、isStep、isDuration…追踪当前解析位置逐段拼装Road对象。MapQuestlink 与 node 双集合重建MapQuest Guidance API v2 返回的是link 集合 node 集合 坐标数组三块分离数据需要靠shapeIndex把节点关联回坐标。finalizeNodes()还会合并无意义的中间节点、累加其距离与耗时MapQuestRoadManager.java#L160-L187最后finalizeRoadShape()裁剪掉起点前、终点后的多余线头。由于不支持备选路线getRoads()固定返回长度为 1 的数组MapQuestRoadManager.java#L153-L158。GraphHopper海拔与备选路线的开关设计GraphHopperRoadManager构造器用alternateAvailable参数声明是否支持备选路线请求时若开启则追加algorithmalternative_routeGraphHopperRoadManager.java#L72-L85。setElevation(true)可让折线解码时携带海拔适合登山徒步类应用。它的指令字段sign是整型-3 到 5用一张小映射表转为统一编码即可。 Road 数据模型抹平四家服务的差异所有服务最终都产出同一个Road对象Road.java这是面向抽象编程能成立的前提双分辨率路线mRouteHigh存全量坐标getRouteLow()惰性调用PointReducer将点数压缩约 10 倍供缩略图或列表场景使用Road.java#L90-L98legs 按需重建Google 直接返回分段而 MapQuest/OSRM 不提供——buildLegs(waypoints)通过找离途经点最近的节点算法统一重建Road.java#L157-L183状态码分级STATUS_OK/STATUS_INVALID无路可走/STATUS_TECHNICAL_ISSUE网络等故障上层据此决定弹技术故障还是此处无路线Parcelable实现了完整序列化可随 Intent 在组件间传递️ 优雅降级请求失败也给你一条直线四个实现都遵循同一条铁律任何异常网络失败、JSON 解析错、无路可走都不抛异常而是返回兜底路线。兜底路线由Road(waypoints)构造器生成Road.java#L72-L85形状只是途经点之间的直线段、距离耗时为 0、状态置为STATUS_TECHNICAL_ISSUE。UI 层因此永远拿得到可绘制对象只需检查状态码决定提示文案。 实战OSMNavigator 里 5 行代码切换路由引擎示例应用 OSMNavigator 的路由更新任务MapActivity.java#L976-L1007完整展示了模板方法的价值——一个 switch 按用户选择的引擎实例化不同的RoadManager统一调用roadManager.getRoads(waypoints)骑行/步行模式不是新类只是给GraphHopperRoadManager追加vehiclebike/vehiclefoot参数拿到Road[]后循环里用RoadManager.buildRoadOverlay(roads[i])画线roads[i].getLengthDurationText()生成12.3 km, 18 min的本地化标签 如何扩展第 5 种路由服务得益于开闭原则新增引擎无需改动基类和任何调用方只需三步继承RoadManager实现getRoad与getRoads两个抽象方法实现私有getUrl(waypoints, getAlternate)拼接请求复用基类的geoPointAsString()和mOptions把服务返回的几何、距离、耗时、转向指令映射到Road/RoadLeg/RoadNode并处理失败时返回new Road(waypoints)兜底总结OSMBonusPack 的路由模块是模板方法模式的教科书式应用基类锁定请求→解析→兜底流程与通用工具参数透传、坐标格式化、路线绘制子类只关心各家 API 的 URL 格式与 JSON/XML 解析细节Road 模型作为统一数据契约配合惰性低分辨率、legs 重建、状态码三级降级机制调用方如 OSMNavigator完全面向抽象切换引擎零成本这套设计让免费开源自托管与商用高质量的路由服务可以并存于同一个应用中值得在做地图 SDK 封装时借鉴。【免费下载链接】osmbonuspackA third-party library of (very) useful additional objects for osmdroid项目地址: https://gitcode.com/gh_mirrors/os/osmbonuspack创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考