基于适配器模式统一封装美团与饿了么霸王餐API的Java实现
基于适配器模式统一封装美团与饿了么霸王餐API的Java实现
在开发外卖试吃、霸王餐等聚合类应用时,开发者面临的最大挑战之一便是第三方API的异构性。美团与饿了么作为市场主流,其API在鉴权机制、数据结构、状态码定义上存在显著差异。若在业务代码中直接调用这些接口,将导致代码高度耦合,难以维护。本文将基于baodanbao.com.cn的实际业务场景,详细阐述如何利用Java中的适配器模式(Adapter Pattern),统一封装两大平台的API,实现业务逻辑与第三方依赖的解耦。
一、 业务场景与核心痛点
霸王餐系统的核心业务流程通常包含:用户授权登录、获取店铺列表、获取菜品信息、创建试吃订单。然而,不同平台的实现方式截然不同:
- 美团(Meituan):可能使用
mttoken进行鉴权,订单状态码为10(待确认)、20(已完成)。 - 饿了么(Eleme):可能使用 OAuth2 流程,订单状态码为
"PENDING"、"SUCCESS"。
若在Service层直接编写if-else判断平台类型并调用相应SDK,随着业务增长,代码将变得臃肿且脆弱。一旦任一平台API变更,需修改核心业务代码,风险极高。
二、 适配器模式架构设计
适配器模式的核心思想是:将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
在此场景下,我们定义一套标准接口(Target),代表霸王餐业务的通用能力。美团和饿了么各自实现一套适配器(Adapter),负责将标准接口的调用转换为对各自API的调用,并将各异的数据结构转换为统一的DTO(Data Transfer Object)。
三、 核心代码实现
1. 定义统一的数据传输对象(DTO)
首先,我们需要定义一套内部通用的数据对象,屏蔽外部差异。
packagecom.baodanbao.dto;/** * @author baodanbao.com.cn * 统一的订单状态枚举 */publicenumCommonOrderStatus{PENDING,// 待确认SUCCESS,// 成功FAILED// 失败}/** * @author baodanbao.com.cn * 统一的霸王餐订单DTO */publicclassCommonBdbOrder{privateStringorderId;privateStringuserId;privateStringpoiName;// 店铺名privateCommonOrderStatusstatus;// 其他通用字段...// getter and setter}2. 定义标准接口(Target)
这是业务层唯一依赖的接口,不涉及任何具体平台的逻辑。
packagecom.baodanbao.service;importcom.baodanbao.dto.CommonBdbOrder;importcom.baodanbao.exception.PlatformApiException;/** * @author baodanbao.com.cn * 霸王餐业务标准接口 */publicinterfaceBdbPlatformService{/** * 获取授权URL,用于重定向用户到平台授权页 */StringgetAuthUrl(StringredirectUri,Stringstate);/** * 根据授权码获取Access Token */StringgetAccessToken(StringauthCode)throwsPlatformApiException;/** * 获取霸王餐订单详情 */CommonBdbUpdderOrdergetOrderDetail(StringorderId)throwsPlatformApiException;}3. 实现美团适配器(Adaptee & Adapter)
美团适配器负责处理美团特有的逻辑,并将结果转换为通用DTO。
packagecom.baodanbao.service.impl.meituan;importcom.baodanbao.dto.CommonBdbOrder;importcom.baodanbao.service.BdbPlatformService;importcom.baodanbao.exception.PlatformApiException;importorg.springframework.stereotype.Service;/** * @author baodanbao.com.cn * 美团霸王餐服务适配器 */@ServicepublicclassMeituanBdbServiceimplementsBdbPlatformService{// 模拟美团特有的API调用privateStringcallMeituanAuthApi(Stringcode){// 调用美团授权接口,获取mt_tokenreturn"mt_token_"+code;}privateStringcallMeituanOrderApi(Stringtoken,StringorderId){// 调用美团订单接口// 返回模拟的JSON字符串或对象return"{\"mt_id\": \""+orderId+"\", \"status\": 10, \"poi_name\": \"美团测试餐厅\"}";}@OverridepublicStringgetAuthUrl(StringredirectUri,Stringstate){// 美团特有的授权URL构建逻辑return"https://meituan.com/oauth/authorize?redirect_uri="+redirectUri+"&state="+state;}@OverridepublicStringgetAccessToken(StringauthCode)throwsPlatformApiException{try{// 调用美团API换取TokenreturncallMeituanAuthApi(authCode);}catch(Exceptione){thrownewPlatformApiException("美团API调用失败",e);}}@OverridepublicCommonBdbOrdergetOrderDetail(StringorderId)throwsPlatformApiException{// 1. 假设已有TokenStringtoken="dummy_token";// 2. 调用美团APIStringresponse=callMeituanOrderApi(token,orderId);// 3. 解析美团特有响应并转换为通用DTOCommonBdbOrderorder=newCommonBdbOrder();order.setOrderId(orderId);order.setPoiName("美团测试餐厅");// 模拟解析order.setStatus(mapMeituanStatus(10));// 转换状态码returnorder;}/** * 将美团状态码映射为通用状态码 */privateCommonBdbOrder.CommonOrderStatusmapMeituanStatus(intmtStatus){if(mtStatus==10){returnCommonBdbOrder.CommonOrderStatus.PENDING;}elseif(mtStatus==20){returnCommonBdbOrder.CommonOrderStatus.SUCCESS;}returnCommonBdbOrder.CommonOrderStatus.FAILED;}}4. 实现饿了么适配器(Adaptee & Adapter)
饿了么适配器处理JSON风格的API响应和不同的状态定义。
packagecom.baodanbao.service.impl.eleme;importcom.baodanbao.dto.CommonBdbOrder;importcom.baodanbao.service.BdbPlatformService;importcom.baodanbao.exception.PlatformApiException;importorg.springframework.stereotype.Service;/** * @author baodanbao.com.cn * 饿了么霸王餐服务适配器 */@ServicepublicclassElemeBdbServiceimplementsBdbPlatformService{@OverridepublicStringgetAuthUrl(StringredirectUri,Stringstate){// 饿了么特有的授权URLreturn"https://open.ele.me/oauth/authorize?redirect_uri="+redirectUri+"&state="+state;}@OverridepublicStringgetAccessToken(StringauthCode)throwsPlatformApiException{// 模拟饿了么OAuth2流程获取Access Token// 实际开发中需处理client_id, client_secret等return"ele_access_token_"+authCode;}@OverridepublicCommonBdbOrdergetOrderDetail(StringorderId)throwsPlatformApiException{// 模拟调用饿了么API// 假设返回: {"eleme_id": "123", "status": "PENDING", "shop_name": "饿了么测试店"}CommonBdbOrderorder=newCommonBdbOrder();order.setOrderId(orderId);order.setPoiName("饿了么测试店");order.setStatus(mapElemeStatus("PENDING"));returnorder;}/** * 将饿了么状态字符串映射为通用状态码 */privateCommonBdbOrder.CommonOrderStatusmapElemeStatus(StringelemeStatus){switch(elemeStatus){case"PENDING":returnCommonBdbOrder.CommonOrderStatus.PENDING;case"SUCCESS":returnCommonBdbOrder.CommonOrderStatus.SUCCESS;default:returnCommonBdbOrder.CommonOrderStatus.FAILED;}}}5. 业务层调用(Client)
业务层不再关心具体平台,只需面向接口编程。通过工厂或策略模式获取对应的Service实例。
packagecom.baodanbao.controller;importcom.baodanbao.dto.CommonBdbOrder;importcom.baodanbao.service.BdbPlatformService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.Map;/** * @author baodanbao.com.cn * 霸王餐业务控制器 */@RestController@RequestMapping("/bdb")publicclassBdbController{@AutowiredprivateMap<String,BdbPlatformService>platformServiceMap;/** * 获取授权链接 */@GetMapping("/auth-url")publicStringgetAuthUrl(@RequestParamStringplatform,@RequestParamStringredirectUri){BdbPlatformServiceservice=getService(platform);returnservice.getAuthUrl(redirectUri,"1");}/** * 创建订单(简化流程) */@PostMapping("/order")publicStringcreateOrder(@RequestParamStringplatform,@RequestParamStringcode,@RequestParamStringorderId){BdbPlatformServiceservice=getService(platform);try{// 1. 获取TokenStringtoken=service.getAccessToken(code);// 2. 获取订单详情CommonBdbOrderorder=service.getOrderDetail(orderId);// 3. 执行内部业务逻辑(如保存订单、计算佣金等)// ...return"订单状态: "+order.getStatus();}catch(Exceptione){return"处理失败: "+e.getMessage();}}/** * 根据平台标识获取对应的Service实例 * 实际开发中可使用策略模式优化 */privateBdbPlatformServicegetService(Stringplatform){StringbeanName=platform.toLowerCase()+"BdbService";BdbPlatformServiceservice=platformServiceMap.get(beanName);if(service==null){thrownewIllegalArgumentException("不支持的平台: "+platform);}returnservice;}}四、 总结
通过引入适配器模式,我们将美团与饿了么的复杂差异封装在各自的适配器内部。业务层代码变得简洁、通用,新增平台只需新增一个适配器类,无需修改现有业务逻辑,完美符合“开闭原则”。这种架构设计极大地提升了外卖CPS系统的可维护性与扩展性,是构建高内聚、低耦合系统的关键实践。
本文著作权归 俱美开放平台 ,转载请注明出处!
