外观模式通过定义统一接口geocoder.reversegeocode()和标准化address结构体,隔离高德/百度api差异,避免参数、字段、错误码耦合,确保新增地图服务时业务代码零修改。

为什么不用外观模式直接调用高德/百度地图API会很快失控
因为两个平台的请求结构、参数命名、错误码体系、返回字段完全不一致,硬编码耦合会导致:同一业务逻辑里反复判断 amap_key 还是 ak,解析 geocodes 还是 result,处理 10000(高德成功)还是 0(百度成功)。改一个平台接口,另一套逻辑就可能悄悄挂掉。
外观模式在这里不是为了“设计感”,而是划出一条清晰边界:对外只暴露 Geocoder.ReverseGeoCode(lat, lng) 这种语义化方法,内部由具体实现类分别对接高德或百度,互不影响。
Go 里怎么写一个最小可用的外观接口
关键不是定义多漂亮的接口,而是让调用方完全感知不到底层差异。接口要窄、稳定、不带平台痕迹:
type Geocoder interface { ReverseGeoCode(lat, lng float64) (Address, error) }-
Address是你定义的统一结构体,字段如Province、City、District、FormattedAddress,不出现adcode或business这类平台私有字段 - 不要在接口里暴露
WithTimeout、WithRetry等配置方法——这些属于具体实现的细节,应通过构造函数传入
示例:
type Address struct {
Province string
City string
District string
Street string
FormattedAddress string
}
高德和百度 SDK 的 HTTP 客户端必须隔离初始化
很多人把共用的 *http.Client 直接塞进外观层,结果高德超时设置成 2s,百度要 5s,一改全崩。更糟的是复用连接池导致 header 污染(比如高德需要 X-Request-ID,百度拒绝这个头)。
立即学习“go语言免费学习笔记(深入)”;
- 每个平台实现类自己 new 一个
*http.Client,并显式设置Timeout、Transport - 高德 API 要求
key放 query,百度要求ak放 query —— 不要试图抽象成 “auth param”,直接在各自实现里拼url.Values - 错误处理不能只看 status code:高德
400可能是 key 错误,百度400可能是坐标格式错,必须解析响应体里的status或info字段再转成统一错误类型
测试时最容易漏掉的三个真实场景
单元测试常只测“成功返回”,但线上出问题基本都在边界上:
- 高德返回
"status":0(表示失败),但 HTTP status 是200;百度同理,"status":302也是200响应 —— 必须检查响应体,不能只看 HTTP 状态码 - 百度逆地理返回的
city字段为空字符串(如海外坐标),但高德会填"未知";统一Address.City时得做空值归一化,否则上层 panic - 高德对坐标精度敏感,
lat=39.9087和lat=39.90870000可能触发不同缓存策略;测试要用真实坐标点,别用0.0, 0.0这种假数据
外观模式的价值不在代码行数减少,而在于把这种平台差异带来的“隐性复杂度”锁死在几个实现文件里。一旦定义好 Geocoder 接口,新增腾讯地图或自建服务,只要实现它,业务代码一行都不用动 —— 但前提是,一开始就没把平台细节泄露到接口或返回结构里。











