适配器模式解决接口不兼容问题,使AlipaySdk、WechatPayV3、StripeClient等第三方支付SDK能被同一套业务逻辑统一调用,通过定义PayInterface并为各SDK编写仅做参数转换、异常映射和返回值标准化的适配器实现。
当你的 PHP 项目要对接多个第三方支付 SDK(比如 AlipaySdk、WechatPayV3、StripeClient),但它们的接口不统一——有的用 pay($order),有的叫 createPayment($data),还有的返回数组而另一个抛异常——这时直接写 if-else 调用会迅速失控。适配器模式不是为了“增强功能”,而是让这些不兼容的类“能被同一套业务逻辑调用”。
核心是定义统一接口,再为每个 SDK 写一个实现该接口的包装类。不要修改原 SDK 源码,也不继承它(除非 SDK 明确支持继承且无副作用)。
常见错误:把适配器写成工厂或门面;或者在适配器里加业务逻辑(比如自动重试、日志埋点),这会让适配器偏离单一职责。
PayInterface::pay() 和 PayInterface::query()
interface PayInterface
{
public function pay(array $order): array;
public function query(string $tradeNo): array;
}
class AlipayAdapter implements PayInterface
{
private $sdk;
public function __construct(\Alipay\AopClient $sdk)
{
$this->sdk = $sdk;
}
public function pay(array $order): array
{
$request = new \Alipay\Request\AlipayTradePagePayRequest();
$request->setBizContent(json_encode([
'out_trade_no' => $order['id'],
'total_amount' => $order['amount'],
'subject' => $order['title'],
]));
$result = $this->sdk->execute($request);
// 把支付宝的 stdClass / array / 异常转成统一 array 结构
return [
'success' => !empty($result->body),
'redirect_url' => $result
->body ?? '',
'raw' => $result,
];
}
public function query(string $tradeNo): array
{
// 实现类似逻辑...
return ['status' => 'paid'];
}
}
如果两个类差异极小(比如只是方法名大小写不同),或你只对接一个 SDK 且确定长期不会换,硬套适配器反而增加维护成本。适配器的价值出现在“变化点”上——SDK 替换、协议升级、多渠道并存。
容易踩的坑:
$sdk->init() 或连接池管理——这属于基础设施层,应由 DI 容器或工厂负责stdClass,有时返回 ArrayObject),导致下游代码反复 is_object() 判断适配器解决的是“接口不兼容”,策略解决的是“算法可替换”。你不会用适配器来切换「微信扫码」和「微信公众号」支付方式——它们本就是同一 SDK 下的不同调用路径,该用策略;但当你把微信支付 SDK 和 Stripe SDK 并列支持时,就必须先用适配器抹平接口差异,再用策略选具体实现。
真实项目里,二者常嵌套使用:策略上下文持有一个 PayInterface,运行时根据渠道配置决定 new 哪个适配器实例。
最易被忽略的一点:适配器的测试不能只测 happy path。必须覆盖原 SDK 抛出的各类异常(网络超时、签名失败、无效参数),并在适配器中映射为统一的 PayException 或错误码字段——否则业务层无法稳定降级。