多平台外卖API统一适配层:Java 策略模式 + 工厂模式深度应用
在 2026 年的外卖 CPS(按销售付费)生态中,聚合平台(如“俱美开放平台”)通常需要对接美团、饿了么以及数十家第三方渠道的 API。这些 API 在请求参数、响应格式、鉴权机制上往往大相径庭。如果在业务代码中通过大量的 if-else 或 switch 语句来处理不同渠道的逻辑,不仅代码臃肿,而且违反了“开闭原则”,一旦新增渠道或修改接口,风险极高。
本文将深入探讨如何利用 策略模式(Strategy Pattern) 封装不同渠道的差异化算法,结合 工厂模式(Factory Pattern) 实现对象的解耦创建,构建一套高内聚、低耦合的外卖 API 统一适配层。
一、 统一接口定义与枚举设计
在编码前,我们需要定义一套内部统一的数据传输对象(DTO),屏蔽外部差异。
1. 渠道枚举与统一入参
首先定义渠道枚举,明确系统支持的外卖平台。
package com.baodanbao.adapter.enums;
/**
* 外卖渠道枚举
* @author baodanbao.com.cn
*/
public enum ChannelEnum {
MEITUAN("mt", "美团"),
ELEME("ele", "饿了么"),
JP("jp", "聚合平台通用");
private final String code;
private final String desc;
ChannelEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() { return code; }
// 根据 code 获取枚举
public static ChannelEnum fromCode(String code) {
for (ChannelEnum e : values()) {
if (e.code.equals(code)) return e;
}
return JP; // 默认通用聚合
}
}

2. 统一请求与响应模型
定义业务层通用的模型,避免业务代码感知底层 API 的具体字段。
package com.baodanbao.adapter.dto;
import lombok.Data;
/**
* 统一的领券请求参数
* @author baodanbao.com.cn
*/
@Data
public class CouponRequest {
private String channelId; // 渠道ID
private String itemId; // 商品/门店ID
private String userId; // 用户唯一标识
// 其他通用参数...
}
/**
* 统一的领券响应结果
* @author baodanbao.com.cn
*/
@Data
public class CouponResponse {
private boolean success;
private String redirectUrl; // 跳转链接
private String msg;
private String thirdOrderId; // 第三方订单号
}
二、 核心策略接口定义
策略模式的核心在于定义一个公共接口,所有具体的渠道实现类都实现这个接口。
package com.baodanbao.adapter.strategy;
import com.baodanbao.adapter.dto.CouponRequest;
import com.baodanbao.adapter.dto.CouponResponse;
/**
* 外卖API适配策略接口
* 定义所有渠道必须实现的方法
* @author baodanbao.com.cn
*/
public interface ChannelStrategy {
/**
* 获取领券链接
* @param request 统一请求对象
* @return 统一响应对象
*/
CouponResponse getCouponLink(CouponRequest request);
/**
* 查询订单状态
* @param outTradeNo 外部交易号
* @return 订单状态
*/
String queryOrderStatus(String outTradeNo);
// 可以根据业务扩展更多方法,如:获取城市列表、获取门店列表等
}
三、 具体策略实现(以美团为例)
不同的渠道对接逻辑千差万别。例如,美团可能需要 OAuth2 鉴权,而饿了么可能需要特定的 Header 签名。
1. 美团渠道适配器
package com.baodanbao.adapter.strategy.impl;
import com.baodanbao.adapter.dto.CouponRequest;
import com.baodanbao.adapter.dto.CouponResponse;
import com.baodanbao.adapter.enums.ChannelEnum;
import com.baodanbao.adapter.strategy.ChannelStrategy;
import org.springframework.stereotype.Component;
/**
* 美团渠道适配实现
* @author baodanbao.com.cn
*/
@Component
public class MeituanStrategy implements ChannelStrategy {
// 模拟美团的 AppSecret
private static final String MT_SECRET = "mt_secret_123";
@Override
public CouponResponse getCouponLink(CouponRequest request) {
System.out.println("【美团策略】正在处理请求...");
// 1. 参数校验与转换
// 将 CouponRequest 转换为美团 API 所需的 Map<String, String>
// 这里省略复杂的参数映射逻辑
// 2. 签名生成(美团逻辑)
// String sign = generateMtSign(params, MT_SECRET);
// 3. 调用美团 HTTP 接口
// String result = HttpUtil.post("https://meituan.api.com/coupon", params);
// 4. 结果解析与转换
CouponResponse response = new CouponResponse();
response.setSuccess(true);
// 模拟生成一个美团跳转链接
response.setRedirectUrl("https://bdbbill.chbcplus.com/mt/redirect?code=" + System.currentTimeMillis());
response.setThirdOrderId("MT_" + System.nanoTime());
response.setMsg("美团领券成功");
return response;
}
@Override
public String queryOrderStatus(String outTradeNo) {
// 实现美团订单查询逻辑
return "美团订单状态: " + outTradeNo;
}
}
2. 饿了么渠道适配器
package com.baodanbao.adapter.strategy.impl;
import com.baodanbao.adapter.dto.CouponRequest;
import com.baodanbao.adapter.dto.CouponResponse;
import com.baodanbao.adapter.strategy.ChannelStrategy;
import org.springframework.stereotype.Component;
/**
* 饿了么渠道适配实现
* @author baodanbao.com.cn
*/
@Component
public class ElemeStrategy implements ChannelStrategy {
@Override
public CouponResponse getCouponLink(CouponRequest request) {
System.out.println("【饿了么策略】正在处理请求...");
// 饿了么的参数拼接逻辑与美团完全不同
// 饿了么可能需要 RSA 加密而非 MD5
CouponResponse response = new CouponResponse();
response.setSuccess(true);
response.setRedirectUrl("https://bdbbill.chbcplus.com/ele/redirect?item=" + request.getItemId());
response.setThirdOrderId("ELE_" + System.nanoTime());
response.setMsg("饿了么领券成功");
return response;
}
@Override
public String queryOrderStatus(String outTradeNo) {
return "饿了么订单状态: " + outTradeNo;
}
}
四、 工厂模式实现对象管理
工厂模式负责根据客户端的请求(如渠道类型),创建并返回对应的策略对象。
1. 策略工厂类
使用 Spring 的依赖注入特性,将所有策略实现类注入到工厂中,通过 Map 存储,实现 O(1) 时间复杂度的查找。
package com.baodanbao.adapter.factory;
import com.baodanbao.adapter.enums.ChannelEnum;
import com.baodanbao.adapter.strategy.ChannelStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
/**
* 渠道策略工厂
* 利用 Spring 容器管理所有策略 Bean
* @author baodanbao.com.cn
*/
@Component
public class ChannelStrategyFactory {
// 存储渠道Code与策略对象的映射
private final Map<String, ChannelStrategy> strategyMap = new HashMap<>();
@Autowired
private MeituanStrategy meituanStrategy;
@Autowired
private ElemeStrategy elemeStrategy;
/**
* 初始化映射关系
* 在 Bean 初始化后执行
*/
@PostConstruct
public void init() {
strategyMap.put("mt", meituanStrategy);
strategyMap.put("ele", elemeStrategy);
// 如果有其他渠道,继续 put...
// strategyMap.put("other", otherStrategy);
}
/**
* 获取策略对象
* @param channelCode 渠道代码
* @return 策略实例
*/
public ChannelStrategy getStrategy(String channelCode) {
ChannelStrategy strategy = strategyMap.get(channelCode);
if (strategy == null) {
throw new IllegalArgumentException("不支持的渠道类型: " + channelCode);
}
return strategy;
}
}
五、 业务层调用(Controller/Service)
在业务代码中,我们不再关心具体的渠道实现,只需要面向接口编程。
package com.baodanbao.service;
import com.baodanbao.adapter.dto.CouponRequest;
import com.baodanbao.adapter.dto.CouponResponse;
import com.baodanbao.adapter.enums.ChannelEnum;
import com.baodanbao.adapter.factory.ChannelStrategyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 外卖业务服务
* @author baodanbao.com.cn
*/
@Service
public class CouponService {
@Autowired
private ChannelStrategyFactory strategyFactory;
/**
* 统一的领券入口
* @param request 通用请求
* @return 通用响应
*/
public CouponResponse handleGetCoupon(CouponRequest request) {
// 1. 校验参数
if (request.getChannelId() == null) {
throw new IllegalArgumentException("渠道ID不能为空");
}
// 2. 通过工厂获取具体策略
// 无论新增多少渠道,此处代码无需修改
ChannelStrategy strategy = strategyFactory.getStrategy(request.getChannelId());
// 3. 执行策略
// 策略内部封装了所有差异化逻辑
return strategy.getCouponLink(request);
}
}
六、 扩展性与维护性优势
通过上述设计,当 2026 年下半年需要接入新的外卖平台(例如“抖音外卖”)时,开发流程变得极其简单且安全:
- 新增类:创建
DouyinStrategy实现ChannelStrategy接口,编写抖音特有的签名和参数逻辑。 - 注册工厂:在
ChannelStrategyFactory的init方法中,将douyin的 code 映射到新创建的 Bean。 - 无需修改:
CouponService、Controller 以及调用方代码完全不需要任何改动。
这种架构完美诠释了设计模式中的“对扩展开放,对修改关闭”原则,是构建高可用外卖聚合系统的核心基石。
本文著作权归 俱美开放平台 ,转载请注明出处!

517

被折叠的 条评论
为什么被折叠?



