关于统一地图组件的一些实践与思考

💬 个人观点(小声说):其实这是公司项目中的需求。说实话,我认为"统一地图组件"在技术层面很难做到完全通用(也可能是我水平不够😅)。不过如果只是满足特定的业务需求场景,其实还是有很大意义的。就像 uni-app 也在尝试做统一 API,思路是一致的。

✨ 背景与诉求

在实际业务开发中,地图功能需求愈发频繁,常常涉及多个地图服务提供商(如高德、华为、Google Maps 等)。由于各家地图 API 在调用方式、数据结构和行为逻辑上存在差异,开发人员往往需要为不同服务重复编写适配代码,造成:

  • ⛓ 高维护成本
  • 🧱 开发效率低
  • 🧩 项目结构混乱、重复代码多

为此,我们希望构建一个 统一地图组件(Map Kit),通过抽象统一的接口,屏蔽地图服务差异,实现一次开发多方运行的目标。

🧨 核心痛点

  • 地图功能在业务中的关键地位:如定位、路径规划、可视化展示等
  • 组件碎片化严重
    • 同一功能需在不同技术栈中多次实现
    • 功能重复、难以复用
    • 缺乏统一的接口规范

🎯 目标与价值

  • 提升开发效率与代码复用率
  • 降低维护成本与技术债务
  • 形成内部地图信息展示组件开发标准化体系

🧭 设计原则

  1. 统一接口抽象:封装主流地图厂商核心 API,屏蔽底层差异
  2. 多厂商支持:兼容高德、华为、Google 等地图服务
  3. 高可配置性:通过配置项控制地图样式、行为、API Key 等
  4. 轻量、低耦合:核心库保持纯粹,业务侧无侵入
  5. 良好开发体验:TypeScript 类型提示、错误提示、调试接口完善
  6. 可扩展、可自定义:支持插件机制,便于二次开发与增强功能

🏗 组件构建思路

📌 核心功能模块

我们不会一开始就囊括所有地图 API,只抽象业务中高频使用的核心能力:

  1. 地图初始化与销毁
  2. 点标记管理(添加、更新、删除)
  3. 路径与线段绘制(如轨迹回放)
  4. 区域绘制(圆形、多边形、矩形)
  5. 地理位置搜索(关键字 / 周边搜索)
  6. 地理编码与逆地理编码
  7. 坐标系转换(WGS-84、GCJ-02、BD-09)

后续会按需迭代如图层控制、热力图、3D 地图等更复杂功能(但我短期内可能不想做😅)。


📐 组件架构分层图

分层说明

📦 业务应用层
  • 使用统一 API 初始化地图
  • 通过暴露的接口进行地图操作
🔧 统一服务 API 层
  • 统一参数结构,提供一致性接口(如 initMap, addMarker
  • 统一错误处理与日志监控
  • 屏蔽底层实现细节,面向业务
🔌 服务适配层
  • 注册机制注入不同服务商的实现
  • 功能模块化拆分(标记、线、面、路径、搜索等)
  • 适配各地图厂商差异,输出统一格式
🌐 原生 API 层
  • 引用地图服务提供商的原生 JavaScript SDK

🧱 组件类图


💻 项目结构说明

📂 文件结构

shell 复制代码
├── demo/                    # 各类地图功能示例
├── src/
│   ├── assets/              # 静态资源(如图标)
│   ├── index.ts             # 统一入口文件
│   ├── mapProvider/         # 地图服务适配层
│   │   ├── amap/            # 高德地图实现
│   │   ├── google/          # Google 地图实现
│   │   ├── huawei/          # 华为地图实现
│   │   ├── commonHandler.ts # 通用逻辑封装
│   │   └── serviceParamsType.ts # 参数类型定义
│   ├── types/               # 接口与类型声明
│   └── utils.ts             # 工具函数
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md

🧭 调用流程图

sequenceDiagram participant User as 业务层 participant Entry as 统一入口 participant Provider as 地图服务适配层 participant Impl as 具体地图实现 User->>Entry: 选择地图类型并初始化 Entry->>Provider: 获取对应 Provider 实例 Provider->>Impl: 调用具体实现(如 addMarker) Impl-->>Provider: 返回结果 Provider-->>Entry: 返回处理结果 Entry-->>User: 返回处理结果

🧠 技术设计亮点

☝ 单一职责原则(SRP)

各功能模块职责清晰,单一管理,便于测试与维护:

ts 复制代码
private baseManager: any        // 基础服务(初始化、缩放等)
private markerManager: any      // 标记服务
private lineManager: any        // 路径服务
private polygonManager: any     // 区域服务
private geometryManager: any    // 几何计算服务
private searchManager: any      // 搜索服务
private geocoderManager: any    // 地理编码服务
private directionManager: any   // 路径规划服务
private coordinateManager: any  // 坐标系转换服务
private widgetManager: any      // 自定义控件(信息窗等)

🧩 注册模式(Registry Pattern)

动态注册服务,实现按需注入、低耦合、插件化:

ts 复制代码
class UnifiedProvider implements IMapProvider {
  static providerSerivces: Record<
    MapProviderEnum,
    Record<MapProviderServiceEnum, any>
  > = {};

  static registerServiceToUnifiedProvider(
    mapProvider: MapProviderEnum,
    serviceName: MapProviderServiceEnum,
    serviceClass: any
  ) {
    if (!this.providerSerivces[mapProvider]) {
      this.providerSerivces[mapProvider] = {};
    }
    this.providerSerivces[mapProvider][serviceName] = serviceClass;
  }
}

// 示例:注册高德地图的 baseManager
UnifiedProvider.registerServiceToUnifiedProvider(
  "amap",
  "baseManager",
  BaseManager
);

🧠 策略模式(Strategy Pattern)

在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法 ,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。

策略模式对应于解决某一问题的一个算法族,允许用户从该算法族中任选一个算法来解决某一问题,同时可以方便地更换算法或者增加新的算法。只要涉及到算法的封装、复用和切换都可以考虑使用策略模式。

以下的策略模式的代码 demo 可能有助于理解。

ts 复制代码
class WeChatPay {
  pay(amount) {
    console.log(`使用微信支付:${amount} 元`);
  }
}

class Alipay {
  pay(amount) {
    console.log(`使用支付宝支付:${amount} 元`);
  }
}

class PaymentContext {
  constructor(strategy) {
    this.strategy = strategy;
  }
  setStrategy(strategy) {
    this.strategy = strategy;
  }
  pay(amount) {
    this.strategy.pay(amount);
  }
}

// 使用方式
const context = new PaymentContext(new WeChatPay());
context.pay(100);
context.setStrategy(new Alipay());
context.pay(200);

在地图组件中,我们可以将不同的地图服务(如 AMap、GoogleMap、HuaweiMap)作为策略类,统一通过 UnifiedProvider 管理切换。

🥲自己写的代码用了什么设计模式都不太清楚,已经快忘光了,还是本科学习的一些知识,还好现在有 gpt帮我写代码和分析代码。


📚 参考资源


📦 仓库地址

🔗 unified-map-kit on GitHub

相关推荐
weixin_471525782 分钟前
【学习嵌入式day-17-数据结构-单向链表/双向链表】
前端·javascript·html
jingling55515 分钟前
Git 常用命令指南:从入门到高效开发
前端·javascript·git·前端框架
索西引擎17 分钟前
【前端】网站favicon图标制作
前端
SelectDB技术团队18 分钟前
ApacheCon Asia 2025 中国开源年度报告:Apache Doris 国内第一
开源·apache·数据库开发·doris·实时分析
小嵌同学19 分钟前
Meson:开源的自动化构建系统
linux·运维·开源·自动化·meson
max50060020 分钟前
基于开源人脸识别模型实现情绪识别功能
python·深度学习·开源·transformer
微凉的衣柜23 分钟前
GitHub Models:为开源AI项目解决推理难题,让AI更易用、更普及
人工智能·开源·github
程序员海军23 分钟前
告别低质量Prompt!:字节跳动PromptPilot深度测评
前端·后端·aigc
华洛24 分钟前
关于可以控制大模型提升任意产品的排名这件事📈
前端·github·产品经理
Yanc26 分钟前
翻了vue源码 终于解决了这个在SFC中使用tsx的bug
前端·vue.js